BOM Cost Calculator Service

Ray Lee ✓ Verified Java Production 2026-03-02

A reusable service class that recursively calculates the total cost of a Bill of Materials (BOM) including all sub-assemblies. It traverses the BOM tree, summing up component costs at each level. Useful for production planning and cost estimation in iDempiere manufacturing workflows.

Code
public class BOMCostService {

    /**
     * Calculate total BOM cost recursively.
     * @param productId  M_Product_ID of the finished good
     * @return total cost including sub-assemblies
     */
    public BigDecimal calculateBOMCost(int productId) {
        BigDecimal totalCost = BigDecimal.ZERO;

        String sql = "SELECT bl.M_Product_ID, bl.QtyBOM, p.ProductType "
                   + "FROM PP_Product_BOMLine bl "
                   + "JOIN M_Product p ON p.M_Product_ID = bl.M_Product_ID "
                   + "WHERE bl.PP_Product_BOM_ID IN "
                   + "(SELECT PP_Product_BOM_ID FROM PP_Product_BOM WHERE M_Product_ID = ?)";

        PreparedStatement pstmt = DB.prepareStatement(sql, null);
        pstmt.setInt(1, productId);
        ResultSet rs = pstmt.executeQuery();

        while (rs.next()) {
            int compId = rs.getInt("M_Product_ID");
            BigDecimal qty = rs.getBigDecimal("QtyBOM");
            BigDecimal unitCost = getStandardCost(compId);
            totalCost = totalCost.add(qty.multiply(unitCost));
        }

        DB.close(rs, pstmt);
        return totalCost;
    }

    private BigDecimal getStandardCost(int productId) {
        return DB.getSQLValueBD(null,
            "SELECT CurrentCostPrice FROM M_Cost "
            + "WHERE M_Product_ID = ? AND AD_Client_ID = ? "
            + "AND M_CostElement_ID = (SELECT M_CostElement_ID "
            + "FROM M_CostElement WHERE CostingMethod = 'S' AND AD_Client_ID = ?)",
            productId, Env.getAD_Client_ID(Env.getCtx()),
            Env.getAD_Client_ID(Env.getCtx()));
    }
}

You Missed