protected BigDecimal getTotalRevenue(NewInvoiceContext invoice) {

    // calculate TOTAL to include result lines
    invoice.calculateTotal();
    BigDecimal invoiceAmountSum = invoice.getTotal();

    // Remove CARRIED BALANCE from tax calculation to avoid double taxation
    LOG.debug("Carried balance is %s", invoice.getCarriedBalance());
    if (null != invoice.getCarriedBalance()) {
      invoiceAmountSum = invoiceAmountSum.subtract(invoice.getCarriedBalance());
    }

    // Remove TAX ITEMS from Invoice to avoid calculating tax on tax
    for (int i = 0; i < invoice.getResultLines().size(); i++) {
      InvoiceLineDTO invoiceLine = (InvoiceLineDTO) invoice.getResultLines().get(i);
      if (null != invoiceLine.getInvoiceLineType()
          && invoiceLine.getInvoiceLineType().getId() == ServerConstants.INVOICE_LINE_TYPE_TAX) {
        invoiceAmountSum = invoiceAmountSum.subtract(invoiceLine.getAmount());
      }
    }

    return invoiceAmountSum;
  }
  /**
   * Creates a Suretax request from inputs from the invoice.
   *
   * @param invoice Invoice for which tax lines need to be calculated.
   * @return Returns instance of com.sapienter.jbilling.client.suretax.request.SuretaxRequest
   * @throws TaskException
   */
  private SuretaxRequest getAssembledRequest(NewInvoiceContext invoice, Integer userId)
      throws TaskException {
    // Construct a suretax request to get the tax lines.
    SuretaxRequest suretaxRequest = new SuretaxRequest();

    // Get the pluggable task parameters here.
    String clientNumber = getParameter(CLIENT_NUMBER, "");
    String validationKey = getParameter(VALIDATION_KEY, "");
    String responseGroup = getParameter(RESPONSE_GROUP, "03");
    String responseType = getParameter(RESPONSE_TYPE, "D");
    String numberOfDecimals = getParameter(NUMBER_OF_DECIMAL, "2");
    Integer dataYear = null;
    Integer dataMonth = null;
    try {
      dataYear = getParameter(DATA_YEAR, Calendar.getInstance().get(Calendar.YEAR));
      dataMonth = getParameter(DATA_MONTH, Calendar.getInstance().get(Calendar.MONTH) + 1);
    } catch (PluggableTaskException e) {
      LOG.debug("Exception while retrieving Data Year or Data Month");
    }

    suretaxRequest.setClientNumber(clientNumber);
    suretaxRequest.setValidationKey(validationKey);
    String uniqueTrackingCode = System.currentTimeMillis() + "";
    suretaxRequest.setClientTracking(uniqueTrackingCode);
    suretaxRequest.setDataMonth(dataMonth.toString());
    suretaxRequest.setDataYear(dataYear.toString());
    suretaxRequest.setIndustryExemption("");
    suretaxRequest.setBusinessUnit("");
    suretaxRequest.setResponseGroup(responseGroup);
    suretaxRequest.setResponseType(responseType + numberOfDecimals);
    suretaxRequest.setReturnFileCode("0");
    suretaxRequest.setTotalRevenue(getTotalRevenue(invoice).floatValue());

    List<LineItem> itemList = new ArrayList<LineItem>();
    for (InvoiceLineDTO invoiceLine : (List<InvoiceLineDTO>) invoice.getResultLines()) {

      if (invoiceLine.getInvoiceLineType().getId()
          != ServerConstants.INVOICE_LINE_TYPE_TAX.intValue()) {

        LOG.debug("Populating itemlist for invoice line: %s", invoiceLine);

        itemList.add(
            getLineItem(invoiceLine.getItem().getId(), invoiceLine, uniqueTrackingCode, userId));
      }
    }
    suretaxRequest.setItemList(itemList);
    return suretaxRequest;
  }
  /** This method is called for populating of the tax lines from the Suretax tax engine. */
  @Override
  public void apply(NewInvoiceContext invoice, Integer userId) throws TaskException {
    this.invoice = invoice;
    // Defaults to rolling back of invoice creation on error.
    boolean rollback_invoice_on_suretax_error = true;
    try {
      rollback_invoice_on_suretax_error = getParameter(ROLLBACK_INVOICE_ON_ERROR, 1) == 1;
    } catch (PluggableTaskException e) {
      // TODO Auto-generated catch block
      e.printStackTrace();
    }

    SuretaxResponse response = null;
    SuretaxRequest suretaxRequest = null;

    boolean errorOccurred = false;
    try {
      suretaxRequest = getAssembledRequest(invoice, userId);

      // Save the suretax json request in the sure_tax_txn_log table

      String jsonRequestString = mapper.writeValueAsString(suretaxRequest);

      suretaxTransactionLogDAS.save(
          new SuretaxTransactionLogDTO(
              suretaxRequest.clientTracking,
              "REQUEST",
              jsonRequestString,
              new Timestamp(System.currentTimeMillis()),
              null,
              "TAX"));
      String suretaxRequestUrl = getParameter(SURETAX_REQUEST_URL, "");
      response = new SuretaxClient().getResponse(suretaxRequest, suretaxRequestUrl);
    } catch (Exception e) {
      if (rollback_invoice_on_suretax_error) throw new TaskException(e);
      else errorOccurred = true;
    }

    // If the control has come here but an error had occurred then
    // the error was meant to be ignored. So, if an error had occurred
    // then just ignore the next block of code. That is exit gracefully
    if (!errorOccurred) {
      // Save the suretax json response in the sure_tax_txn_log table
      int transId = -1;
      try {
        transId = Integer.parseInt(response.transId);
      } catch (Exception e) {
        // TODO: handle exception
      }
      suretaxTransactionLogDAS.save(
          new SuretaxTransactionLogDTO(
              suretaxRequest.clientTracking,
              "RESPONSE",
              response.jsonString,
              new Timestamp(System.currentTimeMillis()),
              transId,
              "TAX"));
      if (response != null && !response.successful.equals("Y")) {
        if (rollback_invoice_on_suretax_error) {
          throw new TaskException(
              "Error while obtaining the tax lines for this invoice:"
                  + response.responseCode
                  + ":"
                  + response.headerMessage);
        }

      } else if (response != null
          && response.successful.equals("Y")
          && response.headerMessage.contains("Success with Item errors")) {
        StringBuffer errorMessages = new StringBuffer("Error messages:[");
        int count = 0;
        for (ItemMessage itemMessage : response.itemMessages) {
          if (count == 0) {
            count++;
          } else {
            errorMessages.append(",");
          }
          errorMessages.append(itemMessage.message);
        }
        errorMessages.append("]");
        if (rollback_invoice_on_suretax_error) {
          throw new TaskException(
              "Error while obtaining the tax lines for this invoice:" + errorMessages.toString());
        }
      } else {
        LOG.debug(
            "Response Code: %s, Header Message: %s, Client Tracking: %s, Total tax: %s, Trans Id: %s",
            response.responseCode,
            response.headerMessage,
            response.clientTracking,
            response.totalTax,
            response.transId);
        OrderDTO order = ((InvoiceLineDTO) invoice.getResultLines().get(0)).getOrder();

        List<InvoiceLineDTO> taxLines = getTaxLines(response, order);
        for (InvoiceLineDTO taxLine : taxLines) {
          invoice.addResultLine(taxLine);
        }
        // Add the trans id in the invoice
        MetaFieldHelper.setMetaField(
            invoice.getEntityId(), invoice, SURETAX_TRANS_ID_META_FIELD_NAME, transId);
      }
    }
  }