public static MOrderLine createOrderLine(
      Properties ctx,
      MOrder order,
      int productId,
      BigDecimal qty,
      BigDecimal discount,
      BigDecimal lineNet)
      throws OperationException {
    if (qty == null) {
      qty = Env.ONE;
    }

    MOrderLine orderLine = new MOrderLine(order);

    MProduct product = new MProduct(ctx, productId, order.get_TrxName());
    MTax tax =
        TaxManager.getTaxFromCategory(ctx, product.getC_TaxCategory_ID(), order.get_TrxName());
    orderLine.setC_Tax_ID(tax.get_ID());
    orderLine.setC_UOM_ID(product.getC_UOM_ID());
    orderLine.setC_BPartner_ID(order.getC_BPartner_ID());
    // Must set Product Id before quantity Ordered.
    orderLine.setM_Product_ID(productId);
    orderLine.setQty(qty);
    orderLine.setPrice();

    // Bug fix, set price to 2dp
    MPriceList orderPriceList = MPriceList.get(ctx, order.getM_PriceList_ID(), order.get_TrxName());

    if (!orderPriceList.isTaxIncluded()) {
      BigDecimal taxAmt = tax.calculateTax(lineNet, true, 12);
      BigDecimal lineNetWithoutTax = lineNet.subtract(taxAmt);
      orderLine.setLineNetAmt(lineNetWithoutTax);

      BigDecimal unitPriceWithoutTax =
          lineNetWithoutTax.divide(qty, 12, BigDecimal.ROUND_HALF_DOWN);

      orderLine.setPriceEntered(unitPriceWithoutTax.setScale(2, BigDecimal.ROUND_HALF_UP));
      orderLine.setPriceActual(unitPriceWithoutTax.setScale(2, BigDecimal.ROUND_HALF_UP));
    } else {
      BigDecimal unitPrice = lineNet.divide(qty, 12, BigDecimal.ROUND_HALF_DOWN);
      orderLine.setLineNetAmt(lineNet.setScale(2, BigDecimal.ROUND_HALF_UP));
      orderLine.setPriceEntered(unitPrice.setScale(2, BigDecimal.ROUND_HALF_UP));
      orderLine.setPriceActual(unitPrice.setScale(2, BigDecimal.ROUND_HALF_UP));
    }

    if (discount.doubleValue() != 0.0) {
      orderLine.setDiscount();
    }

    PoManager.save(orderLine);

    return orderLine;
  }
 /** Set Discount */
 public void setDiscount() {
   BigDecimal list = getPriceList();
   // No List Price
   if (Env.ZERO.compareTo(list) == 0) return;
   // final int precision = getPrecision();
   final int precision = 1; // metas
   // TODO: metas: why we are using precision=1 instead of getPrecision()?
   BigDecimal discount =
       list.subtract(getPriceActual())
           .multiply(new BigDecimal(100))
           .divide(list, precision, BigDecimal.ROUND_HALF_UP);
   setDiscount(discount);
 } // setDiscount