If you take a look at costing sheets within AX 2012 (Company/Inventory and warehouse management/Setup/Costing/Costing Sheets) you will find that this is where the item price costing sheet structure is setup (Cost group id <-> Headers) This will allow you to break down/sum up an items price by costgroupid and then summary/costing headers.
However whenever you try to view the data that will populate your cost sheet via the table BOMCalcTrans you will find that everything is related to the cost group id which is good for displaying the "details" of the costsheet but we sometimes need to summarizes the cost group ids by which header it is under. By using the method bellow you can create a "summary" of your bomcalctrans table.
(note CostGroupHeaderDescription EDT is just a generic str edt I created to store a header group id + description)
This method will only work if you use the header checkbox shown on the Costing sheet setup form listed above under Edit>Identification>Setup>Header
(you can easily can this logic to include the total check box as well or use both fields)
/// <summary>
/// Find the costing header that a cost group id is associated with
/// </summary>
/// <param name="costGroupId">
/// Cost Group Id
/// </param>
/// <returns>
/// Costing Header Code + Description
/// </returns>
/// <remarks>
/// The will pull the header node that a cost group id is under
/// </remarks>
public CostGroupHeaderDescription getCostCategoryByCostGroupId(CostGroupId costGroupId)
{
CostSheetNodeTable costSheetNodesBase, costSheetNodesParent;
boolean foundTotalNode;
CostSheetNodeId currentNodeIdToSearch;
CostGroupCodeAndDescription description;
//find the base instance to find the parent node to see where we need to start the search
select NodeId, ParentNodeId, Code, Description, Total, Header from costSheetNodesBase where costSheetNodesBase.CostGroupId == costGroupId;
//check to see if we are already at the header level when we are at the base
if(costSheetNodesBase.Header == NoYes::Yes)
{
foundTotalNode = true;
description = strFmt("%1 (%2)", costSheetNodesBase.Code, costSheetNodesBase.Description);
}
currentNodeIdToSearch = costSheetNodesBase.ParentNodeId;
//execute this logic until we find a node flagged as header
while(!foundTotalNode)
{
//find the parent nodes record to see if it is a header record
select NodeId, ParentNodeId, Code, Description, Total, Header from costSheetNodesParent where costSheetNodesParent.NodeId == currentNodeIdToSearch;
if(costSheetNodesParent)
{
//check to see if the current node is a header which is the topmost bucket that we need to log
if(costSheetNodesParent.Header == NoYes::Yes)
{
foundTotalNode = true;
description = strFmt("%1 (%2)", costSheetNodesParent.Code, costSheetNodesParent.Description);
}
else
{
//the current node is not a header so we need to get the parent node of the parent
currentNodeIdToSearch = costSheetNodesParent.ParentNodeId;
if(currentNodeIdToSearch == 0)
{
//if we have reached the top most level there has to be a misconfig issue
throw error(strFmt("No header cost sheet node was found for cost group %1 (%2). Please check the configuration of the costsheet", costSheetNodesBase.Code, costSheetNodesBase.Description));
}
}
}
else
{
throw error("There was an issue finding the parent node cost sheet record.");
}
}
return description;
}