Following up on the BOM-explosion: A comment reminded me that I had missed to present the costing techniques to calculate the total costs of each (sub)-product.
Reversing the aggregation direction
What I had shown is how to “aggregate” from parent down to child-level to retrieve the total quantity of each component within a BOM (“How many of each (sub-) components do we have to order (or build) for that bike?”) (1).
Now we reverse the aggregation direction and aggregate the total (!) quantities back up to the parents (2).
And, as this doesn’t make too much sense in an economical way, the second aggregation will be their prices (3). This will give us the sum of all part-costs (“How much will the order of all the parts cost us?”). This is also very useful for planning purposes or reconciliation of prices for intermediate products with your master data.
And if your model holds sales-data as well, you can calculate the totals costs of your total sales within each period. (4)
VAR 1: Using classical hierarchies
Using classical hierarchies, this becomes a fairly easy task: Flatten your hierarchy in the BOMReport-table and create a hierarchy in the datamodel. Then connect it to the DimProducts to retrieve the prices on ComponentID. If it is connected to the Sales-table as well, the measure “TotalCostH” will return the full production costs for all items sold:
- CountPartsH :=
CALCULATE ( SUM ( BOMReport[TotalQty] ), BOMReport[PurchaseItem] <> BLANK () )
- CostPerAssemblyQtyH :=
MAX ( DimProduct[Price] ) * [CountPartsH]
- TotalCostH :=
MAX ( FactSales[Sales] ) * MAX ( DimProduct[Price] )
VAR2: Fully dynamic via bridge-table
If you want to have it fully dynamic and don’t want to create the hierarchies in the datamodel manually, you need to create a bridge-table like in the Easy-P&L, which holds all the rows for aggregation. I had to add the column with the total quantities from the report-table there as well because I couldn’t figure out how to do without. (If you have a clue how to tackle this with a measures instead, please come forward!)
Data model for dynamic hierarchy
Code to create the bridge-table
For every non-purchase item (the final product or any of its assembled sub-components) we are collecting all purchase items that go into it here. Then we expand it to create one row per purchase item for it so that we can connect it to the DimProduct to retrieve the purchase prices.
Download code for bridge-table: BOM2_BridgeTable.txt
Your reports shouldn’t hold any subtotals then, just drag “PathExplode” from the BOMReport into the row-section of your report and add the following measures:
- CountPartsR :=
SUM ( BOMBridgeNew[TotalQty] )
- CostPerAssemblyQtyR :=
SUMX ( BOMBridgeNew, MAX ( DimProduct[Price] ) * BOMBridgeNew[TotalQty] ),
- TotalCostR :=
MAX ( FactSales[Sales] ) * MAX ( DimProduct[Price] )* BOMBridgeNew[TotalQty]),
Look how the filters flow through 4 tables in the last measure (considering that you drag a field from the BOMReport-table into your report): Here the DAX really shines!
Comparison of both methods:
The Hierarchy-version (“H”) will only evaluate values for the components which are purchase-items, while the “Bridge-table-version” (“R”) will evaluate all aggregated values on a row-level. Therefore you cannot use sub-totals in your report.
- In the files attached, for practical reasons the DimProduct and FactSales are created referencing the bridge-table. In real-life, you should of course replace them with the tables from your system.
- The file for VAR2 also holds the solution for VAR within that environment, so you can run it through within the bridge-table datamodel in parallel as well
The last part with BOM-Implosion (“Where Used-Analysis”) is out here.
Enjoy & stay queryious 🙂