/**
   * Retrieve a DefaultTreeModel object that contains the bill of materials (MaterialVO objects) of
   * the specified product.
   */
  public static VOResponse getBillOfMaterials(
      Connection conn,
      CurrenciesBean compCurr,
      ItemPK pk,
      String langId,
      String username,
      ArrayList customizedFields)
      throws Throwable {
    PreparedStatement pstmt = null;
    PreparedStatement pstmt2 = null;
    try {

      String sql1 =
          "select ITM03_COMPONENTS.COMPANY_CODE_SYS01,ITM03_COMPONENTS.ITEM_CODE_ITM01,ITM01_ITEMS.MIN_SELLING_QTY_UM_CODE_REG02,"
              + "ITM03_COMPONENTS.PARENT_ITEM_CODE_ITM01,ITM03_COMPONENTS.QTY,SYS10_COMPANY_TRANSLATIONS.DESCRIPTION "
              + "from ITM03_COMPONENTS,ITM01_ITEMS,SYS10_COMPANY_TRANSLATIONS "
              + "where "
              + "ITM03_COMPONENTS.COMPANY_CODE_SYS01 = ITM01_ITEMS.COMPANY_CODE_SYS01 and "
              + "ITM03_COMPONENTS.ITEM_CODE_ITM01 = ITM01_ITEMS.ITEM_CODE and "
              + "ITM01_ITEMS.COMPANY_CODE_SYS01 = SYS10_COMPANY_TRANSLATIONS.COMPANY_CODE_SYS01 and "
              + "ITM01_ITEMS.PROGRESSIVE_SYS10 = SYS10_COMPANY_TRANSLATIONS.PROGRESSIVE and "
              + "SYS10_COMPANY_TRANSLATIONS.LANGUAGE_CODE=? and ITM03_COMPONENTS.ENABLED='Y' and "
              + "ITM03_COMPONENTS.COMPANY_CODE_SYS01=? and "
              + "ITM03_COMPONENTS.PARENT_ITEM_CODE_ITM01 in (";
      String sql3 = ") order by ITM03_COMPONENTS.PARENT_ITEM_CODE_ITM01,ITM03_COMPONENTS.SEQUENCE";

      Map attribute2dbField = new HashMap();
      attribute2dbField.put("companyCodeSys01ITM03", "ITM03_COMPONENTS.COMPANY_CODE_SYS01");
      attribute2dbField.put("itemCodeItm01ITM03", "ITM03_COMPONENTS.ITEM_CODE_ITM01");
      attribute2dbField.put("parentItemCodeItm01ITM03", "ITM03_COMPONENTS.PARENT_ITEM_CODE_ITM01");
      attribute2dbField.put("descriptionSYS10", "SYS10_COMPANY_TRANSLATIONS.DESCRIPTION");
      attribute2dbField.put("qtyITM03", "ITM03_COMPONENTS.QTY");
      attribute2dbField.put(
          "minSellingQtyUmCodeReg02ITM01", "ITM01_ITEMS.MIN_SELLING_QTY_UM_CODE_REG02");

      ArrayList values = new ArrayList();
      values.add(langId);
      values.add(pk.getCompanyCodeSys01ITM01());

      // retrieve the whole tree...
      MaterialVO compVO = new MaterialVO();
      compVO.setCompanyCodeSys01ITM03(pk.getCompanyCodeSys01ITM01());
      compVO.setDescriptionSYS10("");
      compVO.setItemCodeItm01ITM03(pk.getItemCodeITM01());
      compVO.setQtyITM03(new BigDecimal(1));
      DefaultMutableTreeNode node = new OpenSwingTreeNode(compVO);
      DefaultTreeModel model = new DefaultTreeModel(node);

      String sql2 = "'" + pk.getItemCodeITM01() + "'";
      ArrayList nodes = new ArrayList();
      ArrayList nodes2 = new ArrayList(); // current nodes...
      Hashtable auxnodes = new Hashtable();
      nodes.add(node);

      // read from ITM03 table...
      Response res = null;
      java.util.List rows = null;
      java.util.List auxlist = null;
      DefaultMutableTreeNode auxnode, auxnode2 = null;
      String currentItemCode = null;

      do {
        res =
            QueryUtil.getQuery(
                conn,
                new UserSessionParameters(username),
                sql1 + sql2 + sql3,
                values,
                attribute2dbField,
                MaterialVO.class,
                "Y",
                "N",
                null,
                new GridParams(),
                true);
        if (!res.isError()) {
          rows = ((VOListResponse) res).getRows();
          auxnodes.clear();
          nodes2 = new ArrayList();
          sql2 = "";

          // group items per item code parent...
          for (int i = 0; i < rows.size(); i++) {
            compVO = (MaterialVO) rows.get(i);
            sql2 += "'" + compVO.getItemCodeItm01ITM03() + "',";
            auxnode = new OpenSwingTreeNode(compVO);
            auxlist = (ArrayList) auxnodes.get(compVO.getParentItemCodeItm01ITM03());
            if (auxlist == null) {
              auxlist = new ArrayList();
              auxnodes.put(compVO.getParentItemCodeItm01ITM03(), auxlist);
            }
            auxlist.add(auxnode);
            nodes2.add(auxnode);
          }

          if (sql2.length() > 0) sql2 = sql2.substring(0, sql2.length() - 1);

          // add items to the corresponding parent...
          for (int i = 0; i < nodes.size(); i++) {
            auxnode = (DefaultMutableTreeNode) nodes.get(i);
            compVO = (MaterialVO) auxnode.getUserObject();
            auxlist = (ArrayList) auxnodes.get(compVO.getItemCodeItm01ITM03());
            if (auxlist != null)
              for (int j = 0; j < auxlist.size(); j++) {
                auxnode.add((DefaultMutableTreeNode) auxlist.get(j));
                ((MaterialVO) ((DefaultMutableTreeNode) auxlist.get(j)).getUserObject())
                    .setQtyITM03(
                        ((MaterialVO) ((DefaultMutableTreeNode) auxlist.get(j)).getUserObject())
                            .getQtyITM03()
                            .multiply(((MaterialVO) auxnode.getUserObject()).getQtyITM03())
                            .setScale(5, BigDecimal.ROUND_HALF_UP));
              }
          }

          nodes = nodes2;
        }

      } while (!res.isError() && rows.size() > 0);
      if (res.isError()) throw new Exception(res.getErrorMessage());

      res =
          compCurr.loadCompanyCurrency(
              pk.getCompanyCodeSys01ITM01(), langId, username, customizedFields);
      if (res.isError()) throw new Exception(res.getErrorMessage());
      CurrencyVO currVO = (CurrencyVO) ((VOResponse) res).getVo();

      // navigate through the tree and fetch item prices...
      pstmt =
          conn.prepareStatement(
              "select sum(PUR04_SUPPLIER_PRICES.VALUE),count(PUR04_SUPPLIER_PRICES.VALUE),PUR03_SUPPLIER_PRICELISTS.CURRENCY_CODE_REG03 "
                  + "from PUR04_SUPPLIER_PRICES,PUR03_SUPPLIER_PRICELISTS "
                  + "where "
                  + "PUR04_SUPPLIER_PRICES.COMPANY_CODE_SYS01=PUR03_SUPPLIER_PRICELISTS.COMPANY_CODE_SYS01 and "
                  + "PUR04_SUPPLIER_PRICES.PROGRESSIVE_REG04=PUR03_SUPPLIER_PRICELISTS.PROGRESSIVE_REG04 and "
                  + "PUR04_SUPPLIER_PRICES.PRICELIST_CODE_PUR03=PUR03_SUPPLIER_PRICELISTS.PRICELIST_CODE and "
                  + "PUR04_SUPPLIER_PRICES.COMPANY_CODE_SYS01=? and "
                  + "PUR04_SUPPLIER_PRICES.ITEM_CODE_ITM01=? and "
                  + "PUR04_SUPPLIER_PRICES.START_DATE<=? and "
                  + "PUR04_SUPPLIER_PRICES.END_DATE>=? "
                  + "group by PUR03_SUPPLIER_PRICELISTS.CURRENCY_CODE_REG03");
      pstmt2 =
          conn.prepareStatement(
              "select sum(PRO02_MANUFACTURE_PHASES.VALUE) "
                  + "from PRO02_MANUFACTURE_PHASES,ITM01_ITEMS "
                  + "where "
                  + "PRO02_MANUFACTURE_PHASES.COMPANY_CODE_SYS01=ITM01_ITEMS.COMPANY_CODE_SYS01 and "
                  + "PRO02_MANUFACTURE_PHASES.MANUFACTURE_CODE_PRO01=ITM01_ITEMS.MANUFACTURE_CODE_PRO01 and "
                  + "ITM01_ITEMS.COMPANY_CODE_SYS01=? and "
                  + "ITM01_ITEMS.ITEM_CODE=?");
      res = expandNode(conn, currVO, pstmt, pstmt2, (DefaultMutableTreeNode) model.getRoot());
      if (res.isError()) throw new Exception(res.getErrorMessage());

      return new VOResponse(model);
    } catch (Exception ex1) {
      Logger.error(
          username, "", "getBillOfMaterials", "Error while fetching bill of materials", ex1);
      throw new Exception(ex1.getMessage());
    } finally {
      try {
        pstmt.close();
      } catch (Exception ex) {
      }
      try {
        pstmt2.close();
      } catch (Exception ex) {
      }
    }
  }