private Map<String, Object> makeCall(String json, String method) throws PluggableTaskException {

    LOG.debug("Calling method: '%s', with JSON: %s", method, json);

    MultiValueMap<String, String> postParameters = new LinkedMultiValueMap<String, String>();

    postParameters.add("rest_data", json);
    postParameters.add("input_type", "JSON");
    postParameters.add("method", method);
    postParameters.add("response_type", "JSON");

    RestTemplate restTemplate = new RestTemplate();

    String resultString =
        restTemplate.postForObject(
            ENTRY_POINT,
            postParameters,
            String.class,
            getParameter(PARAM_SERVER.getName()),
            getParameter(PARAM_SUGARINSTANCE.getName()));

    LOG.debug("Result contents: %s", resultString);

    // Tried to use Spring MappingJacksonHttpMessageConverter, but
    // server sends text/html mime type. Using Jackson directly:
    ObjectMapper mapper = new ObjectMapper();
    Map<String, Object> result = null;
    try {
      result = mapper.readValue(resultString, Map.class);
    } catch (IOException ioe) {
      throw new PluggableTaskException(ioe);
    }

    return result;
  }
  /**
   * 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;
  }
  @Override
  protected PaymentTask selectDelegate(PaymentDTOEx paymentInfo) throws PluggableTaskException {
    Integer userId = paymentInfo.getUserId();
    String processorName = getProcessorName(userId);
    if (processorName == null) {
      return null;
    }
    Integer selectedTaskId;
    try {
      // it is a task parameter the id of the processor
      selectedTaskId = intValueOf(parameters.get(processorName));
    } catch (NumberFormatException e) {
      throw new PluggableTaskException(
          "Invalid payment task id :" + processorName + " for userId: " + userId);
    }
    if (selectedTaskId == null) {
      LOG.warn("Could not find processor for " + parameters.get(processorName));
      return null;
    }

    LOG.debug("Delegating to task id " + selectedTaskId);
    PaymentTask selectedTask = instantiateTask(selectedTaskId);

    return selectedTask;
  }
  /**
   * Un-subscribes a customer from all plans held by the given "plan subscription" item, removing
   * all plan item prices from the customer price map.
   *
   * @param userId user id of the customer to un-subscribe
   * @param itemId item representing the subscription to a plan
   */
  public static void unsubscribe(Integer userId, Integer itemId) {
    LOG.debug("Un-subscribing customer %s from plan subscription item %s", userId, itemId);

    CustomerPriceBL customerPriceBl = new CustomerPriceBL(userId);
    for (PlanDTO plan : new PlanBL().getPlansBySubscriptionItem(itemId))
      customerPriceBl.removePrices(plan.getId());
  }
  // use it when you need only currency objects
  public List<CurrencyDTO> getCurrenciesWithoutRates(
      Integer languageId, Integer entityId, boolean inUseOnly)
      throws NamingException, SQLException {

    String cacheKey = "without rates " + getCacheKey(languageId, entityId, new Date());
    List<CurrencyDTO> cachedCurrencies =
        (List<CurrencyDTO>) cache.getFromCache(cacheKey, cacheModel);

    if (cachedCurrencies != null && !cachedCurrencies.isEmpty()) {
      LOG.debug("Cache hit for %s", cacheKey);
      return cachedCurrencies;
    }

    List<CurrencyDTO> currencies = new CurrencyDAS().findAll();

    boolean inUse;
    for (CurrencyDTO currency : currencies) {
      set(currency.getId());
      inUse = entityHasCurrency(entityId, currency.getId());
      if (inUseOnly && !inUse) continue;
      currency.setInUse(inUse);
      currency.setName(this.currency.getDescription(languageId));

      // find system rate
      if (currency.getId() == SYSTEM_CURRENCY_ID.intValue()) {
        currency.setSysRate(SYSTEM_CURRENCY_RATE_DEFAULT);
      }
    }
    cache.putInCache(cacheKey, cacheModel, currencies);
    return currencies;
  }
 /**
  * Removes all customer prices for the plan's current set of plan items. This will remove prices
  * for subscribed customers AND orphaned prices where the customers order has been deleted in a
  * non-standard way (DB delete, non API usage).
  */
 public void purgeCustomerPrices() {
   if (plan != null) {
     LOG.debug("Removing ALL remaining customer prices for plan %s", plan.getId());
     new CustomerPriceBL().removeAllPrices(plan.getPlanItems());
   } else {
     LOG.error("Cannot purge customer prices, PlanDTO not found or not set!");
   }
 }
  /**
   * Called for every object that was skipped. Increments total users failed value in context and
   * adds user id to failed user list in context.
   */
  @Override
  public void onSkipInProcess(Object obj, Throwable th) {
    Integer userId = (Integer) obj;

    Integer billingProcessId =
        this.getIntegerFromContext(Constants.JOBCONTEXT_BILLING_PROCESS_ID_KEY);

    logger.debug(
        "BillingProcessId # "
            + billingProcessId
            + " || UserId # "
            + userId
            + " +++ Entering onSkipProcess()");
    logger.info(
        "BillingProcessId # "
            + billingProcessId
            + " || UserId # "
            + userId
            + " +++ Skipped due to Exception # "
            + th);

    Integer failed = this.getIntegerFromContext(Constants.JOBCONTEXT_TOTAL_USERS_FAILED_KEY);
    this.addIntegerToContext(Constants.JOBCONTEXT_TOTAL_USERS_FAILED_KEY, failed + 1);
    List<Integer> list = this.getIntegerListFromContext(Constants.JOBCONTEXT_FAILED_USERS_LIST_KEY);
    synchronized (list) {
      list.add(userId);
      logger.debug(
          "BillingProcessId # "
              + billingProcessId
              + " || UserId # "
              + userId
              + " +++ Failed users list size # "
              + list.size());
      this.addIntegerListToContext(Constants.JOBCONTEXT_FAILED_USERS_LIST_KEY, list);
    }

    local.addProcessRunUser(billingProcessId, userId, ProcessRunUserDTO.STATUS_FAILED);
    logger.debug(
        "BillingProcessId # "
            + billingProcessId
            + " || UserId # "
            + userId
            + " +++ Leaving onSkipProcess()");
  }
  /**
   * Subscribes a customer to this plan, adding all plan item prices to the customer price map.
   *
   * @param userId user id of the customer to subscribe
   * @return list of saved customer price entries, empty if no prices applied to customer.
   */
  public List<CustomerPriceDTO> subscribe(Integer userId) {
    LOG.debug("Subscribing customer %s to plan %s", userId, plan.getId());

    List<CustomerPriceDTO> saved = new ArrayList<CustomerPriceDTO>();

    CustomerPriceBL customerPriceBl = new CustomerPriceBL(userId);
    saved.addAll(customerPriceBl.addPrices(plan.getPlanItems()));

    return saved;
  }
 /**
  * restarts a failed job
  *
  * @param billingProcessId : id of the failed billing process
  * @param entityId : id of the entity to which billing process belongs
  * @return : true - if restart was successful
  */
 public boolean restartFailedJobByBillingProcessId(
     Integer billingProcessId, final Integer entityId) {
   logger.debug("Entering restartFailedJobByBillingProcessId() with id # " + billingProcessId);
   final Date jobRunDate =
       this.getDateFromJbParametersByExecutionId(
           this.getExecutionIdByBillingProcessId(billingProcessId));
   if (jobRunDate != null) {
     Thread restartThread =
         new Thread() {
           @Override
           public void run() {
             getProcessBean().trigger(jobRunDate, entityId);
           }
         };
     restartThread.start();
     return true;
   }
   logger.debug("Job Restart was successful...job running in background");
   return false;
 }
  /**
   * Subscribes a customer to all plans held by the given "plan subscription" item, adding all plan
   * item prices to a customer price map.
   *
   * @param userId user id of the customer to subscribe
   * @param itemId item representing the subscription to a plan
   * @return list of saved customer price entries, empty if no prices applied to customer.
   */
  public static List<CustomerPriceDTO> subscribe(Integer userId, Integer itemId) {
    LOG.debug("Subscribing customer %s to plan subscription item %s", userId, itemId);

    List<CustomerPriceDTO> saved = new ArrayList<CustomerPriceDTO>();

    CustomerPriceBL customerPriceBl = new CustomerPriceBL(userId);
    for (PlanDTO plan : new PlanBL().getPlansBySubscriptionItem(itemId))
      saved.addAll(customerPriceBl.addPrices(plan.getPlanItems()));

    return saved;
  }
  public void trigger() throws SessionInternalError {
    LOG.debug("calling ProvisioningProcessSessionBean trigger() method");

    try {
      ProvisioningProcessBL processBL = new ProvisioningProcessBL();

      processBL.activateOrders();
      processBL.deActivateOrders();
    } catch (Exception e) {
      throw new SessionInternalError(e);
    }
  }
  /**
   * Converts all currencies to Pivot currency i.e. 1
   *
   * @param currencyId
   * @param amount
   * @param toDate
   * @param entityId
   * @return
   * @throws SessionInternalError
   */
  private BigDecimal convertToPivot(
      Integer currencyId, BigDecimal amount, Date toDate, Integer entityId)
      throws SessionInternalError {
    if (currencyId.equals(SYSTEM_CURRENCY_ID)) {
      LOG.debug("this currency is already in the pivot");
      return amount;
    }

    // make the conversion itself
    CurrencyExchangeDTO exchange = findExchange(entityId, currencyId, toDate);
    return amount.divide(
        exchange.getRate(), Constants.BIGDECIMAL_SCALE, Constants.BIGDECIMAL_ROUND);
  }
  /**
   * Refreshes the customer plan item price mappings for all customers that have subscribed to this
   * plan. This method will remove all existing prices for the plan and insert the current list of
   * plan items into the customer price map.
   */
  public void refreshCustomerPrices() {
    if (plan != null) {
      LOG.debug("Refreshing customer prices for subscribers to plan %s", plan.getId());

      for (CustomerDTO customer : getCustomersByPlan(plan.getId())) {
        CustomerPriceBL bl = new CustomerPriceBL(customer);
        bl.removePrices(plan.getId());
        bl.addPrices(plan.getPlanItems());
      }
    } else {
      LOG.error("Cannot update customer prices, PlanDTO not found or not set!");
    }
  }
  private CurrencyExchangeDTO findExchange(Integer entityId, Integer currencyId, Date toDate)
      throws SessionInternalError {

    // check for system currency exchange
    if (SYSTEM_CURRENCY_ID.equals(currencyId)) {
      return new CurrencyExchangeDTO(
          0, currency, entityId, SYSTEM_CURRENCY_RATE_DEFAULT, new Date());
    }
    LOG.debug("Get exchange rate for %s for entity %s for date %s", currencyId, entityId, toDate);

    CurrencyExchangeDTO exchange = exchangeDas.getExchangeRateForDate(entityId, currencyId, toDate);
    if (exchange == null) {
      // this entity doesn't have this exchange defined
      // 0 is the default, don't try to use null, it won't work
      exchange = exchangeDas.findExchange(SYSTEM_RATE_ENTITY_ID, currencyId);
      if (exchange == null) {
        throw new SessionInternalError(
            "Currency " + currencyId + " doesn't have a default exchange");
      }
    }
    LOG.debug("Exchange found %s", exchange.getId());
    return exchange;
  }
  /*
     Currency conversion
  */
  public BigDecimal convert(
      Integer fromCurrencyId,
      Integer toCurrencyId,
      BigDecimal amount,
      Date toDate,
      Integer entityId)
      throws SessionInternalError {

    LOG.debug(
        "Converting %s to %s , amount %s ,entity %s",
        fromCurrencyId, toCurrencyId, amount, entityId);
    if (fromCurrencyId.equals(toCurrencyId)) {
      return amount; // mmm.. no conversion needed
    }

    if (amount.compareTo(BigDecimal.ZERO) == 0) {
      return BigDecimal.ZERO; // mmm.. conversion doth not make sense
    }

    // make the conversions
    final BigDecimal pivotAmount = convertToPivot(fromCurrencyId, amount, toDate, entityId);
    LOG.debug("Pivot Amount %s", pivotAmount);
    return convertPivotToCurrency(toCurrencyId, pivotAmount, toDate, entityId);
  }
  public void onMessage(Message message) {
    try {
      LOG.debug("Received a message");

      // use a session bean to make sure the processing is done in
      // a transaction
      IProvisioningProcessSessionBean provisioning =
          (IProvisioningProcessSessionBean)
              Context.getBean(Context.Name.PROVISIONING_PROCESS_SESSION);

      provisioning.externalProvisioning(message);
    } catch (Exception e) {
      throw new SessionInternalError(e);
    }
  }
  public static List<OrderLineDTO> diffOrderLines(
      List<OrderLineDTO> lines1, List<OrderLineDTO> lines2) {

    List<OrderLineDTO> diffLines = new ArrayList<OrderLineDTO>();

    Collections.sort(
        lines1,
        new Comparator<OrderLineDTO>() {
          public int compare(OrderLineDTO a, OrderLineDTO b) {
            return new Integer(a.getId()).compareTo(b.getId());
          }
        });

    for (OrderLineDTO line : lines2) {
      int index =
          Collections.binarySearch(
              lines1,
              line,
              new Comparator<OrderLineDTO>() {
                public int compare(OrderLineDTO a, OrderLineDTO b) {
                  return new Integer(a.getId()).compareTo(b.getId());
                }
              });

      if (index >= 0) {
        // existing line
        OrderLineDTO diffLine = new OrderLineDTO(lines1.get(index));

        // will fail if amounts or quantities are null...
        diffLine.setAmount(line.getAmount().subtract(diffLine.getAmount()));
        diffLine.setQuantity(line.getQuantity().subtract(diffLine.getQuantity()));

        if (BigDecimal.ZERO.compareTo(diffLine.getAmount()) != 0
            || BigDecimal.ZERO.compareTo(diffLine.getQuantity()) != 0) {
          diffLines.add(diffLine);
        }
      } else {
        // new line
        diffLines.add(new OrderLineDTO(line));
      }
    }

    LOG.debug("Diff lines are %s", diffLines);
    return diffLines;
  }
  public void addPrice(PlanItemDTO planItem) {
    if (plan != null) {
      PriceModelBL.validateAttributes(planItem.getModels().values());

      plan.addPlanItem(planItem);

      LOG.debug("Saving updates to plan %s", plan.getId());
      this.plan = planDas.save(plan);

      refreshCustomerPrices();

      // trigger internal event
      EventManager.process(new PlanUpdatedEvent(plan));

    } else {
      LOG.error("Cannot add price, PlanDTO not found or not set!");
    }
  }
  public List<CurrencyDTO> getCurrenciesToDate(Integer languageId, Integer entityId, Date to)
      throws NamingException, SQLException {

    String cacheKey = getCacheKey(languageId, entityId, to);
    List<CurrencyDTO> cachedCurrencies =
        (List<CurrencyDTO>) cache.getFromCache(cacheKey, cacheModel);

    if (cachedCurrencies != null && !cachedCurrencies.isEmpty()) {
      LOG.debug("Cache hit for %s", cacheKey);
      return cachedCurrencies;
    }

    List<CurrencyDTO> currencies = new CurrencyDAS().findAll();

    for (CurrencyDTO currency : currencies) {
      set(currency.getId());
      currency.setName(this.currency.getDescription(languageId));

      // find system rate
      if (currency.getId() == SYSTEM_CURRENCY_ID.intValue()) {
        currency.setSysRate(SYSTEM_CURRENCY_RATE_DEFAULT);
      } else {
        final CurrencyExchangeDTO exchangeRateForDate =
            findExchange(SYSTEM_RATE_ENTITY_ID, currency.getId(), to);
        currency.setSysRate(exchangeRateForDate.getRate());
      }

      // find entity specific rate
      CurrencyExchangeDTO exchange =
          exchangeDas.getExchangeRateForDate(entityId, currency.getId(), to);
      if (exchange != null) {
        currency.setRate(exchange.getRate().toString());
      }

      // set in-use flag
      currency.setInUse(entityHasCurrency(entityId, currency.getId()));
    }

    cache.putInCache(cacheKey, cacheModel, currencies);

    return currencies;
  }
  @Override
  protected PaymentTask selectDelegate(PaymentDTOEx paymentInfo) throws PluggableTaskException {
    String currencyCode = paymentInfo.getCurrency().getCode();
    Integer selectedTaskId = null;

    try {
      // try to get the task id for this currency
      selectedTaskId = intValueOf(parameters.get(currencyCode));
    } catch (NumberFormatException e) {
      throw new PluggableTaskException("Invalid task id for currency " + "code: " + currencyCode);
    }
    if (selectedTaskId == null) {
      LOG.warn("Could not find processor for " + parameters.get(currencyCode));
      return null;
    }

    LOG.debug("Delegating to task id " + selectedTaskId);
    PaymentTask selectedTask = instantiateTask(selectedTaskId);

    return selectedTask;
  }
  public void updateProvisioningStatus(Integer in_order_id, Integer in_order_line_id, String result)
      throws EmptyResultDataAccessException {

    OrderDAS orderDb = new OrderDAS();
    OrderDTO order = orderDb.find(in_order_id);
    OrderBL order_bl = new OrderBL(order);

    OrderLineDAS lineDAS = new OrderLineDAS();
    OrderLineDTO order_line =
        lineDAS.findForUpdate(in_order_line_id); // lineDb.findNow(in_order_line_id);

    if (order_line == null) {
      throw new EmptyResultDataAccessException("Didn't find order line: " + in_order_line_id, 1);
    }
    LOG.debug("update order line : " + order_line.getId());

    if (result.equals("fail")) {
      order_bl.setProvisioningStatus(in_order_line_id, Constants.PROVISIONING_STATUS_FAILED);
      LOG.debug("Provisioning status set to 'FAILED' for order line : " + order_line.getId());
    } else if (result.equals("unavailable")) {
      order_bl.setProvisioningStatus(in_order_line_id, Constants.PROVISIONING_STATUS_UNAVAILABLE);
      LOG.debug("Provisioning status set to 'UNAVAILABLE' for order line : " + order_line.getId());
    } else if (result.equals("success")) {
      LOG.debug("order line Status before : " + order_line.getProvisioningStatusId());
      if (order_line
          .getProvisioningStatusId()
          .equals(Constants.PROVISIONING_STATUS_PENDING_ACTIVE)) {
        order_bl.setProvisioningStatus(in_order_line_id, Constants.PROVISIONING_STATUS_ACTIVE);
        LOG.debug("Provisioning status set to 'ACTIVE' for order line : " + order_line.getId());
      } else if (order_line
          .getProvisioningStatusId()
          .equals(Constants.PROVISIONING_STATUS_PENDING_INACTIVE)) {
        order_bl.setProvisioningStatus(in_order_line_id, Constants.PROVISIONING_STATUS_INACTIVE);
        LOG.debug("Provisioning status set to 'INACTIVE' for order line : " + order_line.getId());
      } else {
        throw new SessionInternalError(
            "Invalid or unexpected "
                + "provisioning status: "
                + order_line.getProvisioningStatusId());
      }
    } else {
      throw new SessionInternalError(
          "Can not process message with " + "result property value " + result);
    }

    lineDAS.flush();
  }
  public void update(PlanDTO dto) {
    if (plan != null) {

      // un-subscribe existing customers before updating
      List<CustomerDTO> subscribers = getCustomersByPlan(plan.getId());
      for (CustomerDTO customer : subscribers) {
        unsubscribe(customer.getBaseUser().getUserId());
      }

      // clean all remaining prices just-in-case there's an orphaned record
      if (plan.getPlanItems().size() > 0) {
        purgeCustomerPrices();
      }

      // do update
      validateAttributes(dto);

      plan.setDescription(dto.getDescription());
      plan.setItem(dto.getItem());
      plan.setPeriod(dto.getPeriod());

      plan.getPlanItems().clear();
      plan.getPlanItems().addAll(dto.getPlanItems());

      LOG.debug("Saving updates to plan %s", plan.getId());
      this.plan = planDas.save(plan);

      // re-subscribe customers after plan has been saved
      for (CustomerDTO customer : subscribers) {
        subscribe(customer.getBaseUser().getUserId());
      }

      // trigger internal event
      EventManager.process(new PlanUpdatedEvent(plan));

    } else {
      LOG.error("Cannot update, PlanDTO not found or not set!");
    }
  }
  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;
  }
  public static void addLine(OrderDTO order, OrderLineDTO line, boolean persist) {
    if (persist)
      throw new IllegalArgumentException("persist is oboleted"); // TODO remove the argument
    UserBL user = new UserBL(order.getUserId());
    OrderLineDTO oldLine = order.getLine(line.getItemId());
    if (oldLine != null) {
      // get a copy of the old line
      oldLine = new OrderLineDTO(oldLine);
    }

    addItem(
        line.getItemId(),
        line.getQuantity(),
        user.getLanguage(),
        order.getUserId(),
        order.getCurrencyId(),
        order,
        line,
        persist);

    if (persist) {
      // generate NewQuantityEvent
      OrderLineDTO newLine = order.getLine(line.getItemId());
      OrderBL orderBl = new OrderBL();
      List<OrderLineDTO> oldLines = new ArrayList<OrderLineDTO>(1);
      List<OrderLineDTO> newLines = new ArrayList<OrderLineDTO>(1);
      if (oldLine != null) {
        oldLines.add(oldLine);
      }
      newLines.add(newLine);
      LOG.debug("Old line: %s", oldLine);
      LOG.debug("New line: %s", newLine);
      orderBl.checkOrderLineQuantities(
          oldLines, newLines, user.getEntity().getEntity().getId(), order.getId(), true);
    }
  }
  public boolean process(PaymentDTOEx paymentInfo) throws PluggableTaskException {
    FormatLogger log = new FormatLogger(Logger.getLogger(PaymentEmailAuthorizeNetTask.class));
    boolean retValue = super.process(paymentInfo);
    String address = (String) parameters.get(PARAMETER_EMAIL_ADDRESS.getName());
    try {
      UserBL user = new UserBL(paymentInfo.getUserId());
      String message;
      if (new Integer(paymentInfo.getPaymentResult().getId()).equals(Constants.RESULT_OK)) {
        message = "payment.success";
      } else {
        message = "payment.fail";
      }
      String params[] = new String[6];
      params[0] = paymentInfo.getUserId().toString();
      params[1] = user.getEntity().getUserName();
      params[2] = paymentInfo.getId() + "";
      params[3] = paymentInfo.getAmount().toString();
      if (paymentInfo.getAuthorization() != null) {
        params[4] = paymentInfo.getAuthorization().getTransactionId();
        params[5] = paymentInfo.getAuthorization().getApprovalCode();
      } else {
        params[4] = "Not available";
        params[5] = "Not available";
      }
      log.debug(
          "Bkp 6 " + params[0] + " " + params[1] + " " + params[2] + " " + params[3] + " "
              + params[4] + " " + params[5] + " ");
      NotificationBL.sendSapienterEmail(
          address, user.getEntity().getEntity().getId(), message, null, params);
    } catch (Exception e) {

      log.warn("Cant send receit email");
    }

    return retValue;
  }
  /** 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);
      }
    }
  }
  private LineItem getLineItem(
      Integer itemId, InvoiceLineDTO invoiceLine, String uniqueTrackingCode, Integer userId)
      throws TaskException {
    // Get the meta field names
    String secondaryZipCodeExtensionFieldname =
        getParameter(SECONDARY_ZIP_CODE_EXTN_FIELDNAME, "Secondary Zip code extension");
    String secondaryZipCodeFieldname =
        getParameter(SECONDARY_ZIP_CODE_FIELDNAME, "Secondary Zip code");
    String billingZipCodeFieldname =
        getParameter(BILLING_ZIP_CODE_FIELDNAME, "Billing Zip code extension");
    String regulatoryCodeFieldname = getParameter(REGULATORY_CODE_FIELDNAME, "Regulatory Code");
    String salesTypeCodeFieldname = getParameter(SALES_TYPE_CODE_FIELDNAME, "Sales Type Code");
    String taxExemptionCodeFieldname =
        getParameter(TAX_EXEMPTION_CODE_FIELDNAME, "Tax exemption code");
    String transactionTypeCodeFieldname =
        getParameter(TRANSACTION_TYPE_CODE_FIELDNAME, "Transaction Type Code");

    LineItem lineItem = new LineItem();
    lineItem.setBillToNumber(""); // TODO: need to be addressed ?
    String customerNumber = null;
    List<NewInvoiceContext.OrderContext> orders = invoice.getOrders();
    // We need to get the fresh item from the database because
    // the item in the invoiceLine doesn't yet contain meta fields.
    ItemDTO item = new ItemDAS().find(itemId);
    OrderDTO orderDTO = null;
    UserDTO invoiceToUser = null;
    for (NewInvoiceContext.OrderContext orderCtx : orders) {
      if (orderCtx.order.getId().intValue() == invoiceLine.getOrder().getId()) {
        orderDTO = orderCtx.order;
        break;
      }
    }

    if (null == orderDTO) {
      orderDTO = orders.get(0).order;
    }

    invoiceToUser = new UserDAS().find(userId);
    customerNumber = invoiceToUser.getCustomer().getId() + "";

    lineItem.setCustomerNumber(customerNumber);
    lineItem.setInvoiceNumber("JB" + uniqueTrackingCode);
    lineItem.setLineNumber(""); // TODO: need to be addressed ?
    lineItem.setOrigNumber(""); // TODO: need to be addressed ?

    MetaFieldValue<String> p2PPlus4 =
        invoiceToUser.getCustomer().getMetaField(secondaryZipCodeExtensionFieldname);
    if (p2PPlus4 != null) {
      lineItem.setP2PPlus4(p2PPlus4.getValue());
    } else {
      lineItem.setP2PPlus4("");
    }

    MetaFieldValue<String> p2PZipcode =
        invoiceToUser.getCustomer().getMetaField(secondaryZipCodeFieldname);
    if (p2PZipcode != null) {
      lineItem.setP2PZipcode(p2PZipcode.getValue());
    } else {
      lineItem.setP2PZipcode("");
    }

    MetaFieldValue<String> plus4 =
        invoiceToUser.getCustomer().getMetaField(billingZipCodeFieldname);
    if (plus4 != null) {
      lineItem.setPlus4(plus4.getValue());
    } else {
      lineItem.setPlus4("");
    }

    LOG.debug("Meta fields: p2PPlus4: %s, p2PZipcode: %s, plus4:%s", p2PPlus4, p2PZipcode, plus4);

    MetaFieldValue<String> regulatoryCode = null;
    regulatoryCode = item.getMetaField(regulatoryCodeFieldname);
    if (regulatoryCode == null
        || regulatoryCode.getValue() == null
        || regulatoryCode.getValue().isEmpty()) {
      lineItem.setRegulatoryCode("00");
    } else {
      lineItem.setRegulatoryCode(regulatoryCode.getValue());
    }

    lineItem.setRevenue(invoiceLine.getAmount().floatValue());

    MetaFieldValue<String> salesTypeCode = orderDTO.getMetaField(salesTypeCodeFieldname);
    if (salesTypeCode == null
        || salesTypeCode.getValue() == null
        || salesTypeCode.getValue().isEmpty()) {
      lineItem.setSalesTypeCode("R");
    } else {
      lineItem.setSalesTypeCode(salesTypeCode.getValue());
    }

    lineItem.setSeconds(
        invoiceLine.getQuantity() != null ? invoiceLine.getQuantity().intValue() : 0);
    List<String> taxExemptionCodeList = new ArrayList<String>();
    // First get the tax exemption code from the customer
    MetaFieldValue<String> taxExemptionCode =
        invoiceToUser.getCustomer().getMetaField(taxExemptionCodeFieldname);
    LOG.debug("Tax exemption code from customer: %s", taxExemptionCode);
    if (!(taxExemptionCode != null
        && taxExemptionCode.getValue() != null
        && !taxExemptionCode.getValue().isEmpty())) {
      taxExemptionCode = item.getMetaField(taxExemptionCodeFieldname);
      LOG.debug("Tax exemption code from product: %s", taxExemptionCode);
    }
    if (taxExemptionCode == null) {
      LOG.debug("Setting tax exemption code to be 00");
      taxExemptionCodeList.add("00");
    } else {
      taxExemptionCodeList.add(taxExemptionCode.getValue());
    }
    LOG.debug(
        "Meta fields: regulatoryCode: %s, salesTypeCode: %s, taxExemptionCode: %s",
        regulatoryCode, salesTypeCode, taxExemptionCode);
    lineItem.setTaxExemptionCodeList(taxExemptionCodeList);
    lineItem.setTaxIncludedCode("0");

    lineItem.setTermNumber("");

    // TODO: Need to check if trans date will be current date or based on data year and data month ?
    lineItem.setTransDate("07-10-2012");

    MetaFieldValue<String> transTypeCode = null;
    transTypeCode = item.getMetaField(transactionTypeCodeFieldname);

    if (transTypeCode == null
        || transTypeCode.getValue() == null
        || transTypeCode.getValue().isEmpty()) {
      throw new SessionInternalError(
          "No valid transaction type code found on the product",
          new String[] {"ItemDTOEx,transTypeCode,no.valid.transactionTypeCode.on.product"});
    }
    lineItem.setTransTypeCode(transTypeCode.getValue());
    lineItem.setUnits(invoiceLine.getQuantity() != null ? invoiceLine.getQuantity().intValue() : 0);
    lineItem.setUnitType("00");

    if (invoiceToUser.getContact().getPostalCode() != null
        && plus4 != null
        && plus4.getValue() != null
        && !plus4.getValue().isEmpty()) {
      lineItem.setZipcode(invoiceToUser.getContact().getPostalCode());
      lineItem.setTaxSitusRule("05");
    } else if (invoiceToUser.getContact().getPostalCode() != null
        && (plus4 == null || plus4.getValue() == null || plus4.getValue().isEmpty())) {
      lineItem.setZipcode(invoiceToUser.getContact().getPostalCode());
      lineItem.setPlus4("0000");
      lineItem.setTaxSitusRule("05");
    }
    return lineItem;
  }
 public void invalidateCache() {
   LOG.debug("Invalidating currency cache");
   cache.flushCache(flushModel);
 }
 /**
  * returns start date of the execution provided execution id
  *
  * @param jobExecutionId : id of the job execution
  * @return Date : start date of execution
  */
 public Date getStartDate(Integer jobExecutionId) {
   logger.debug("Entering getStartDate()");
   JobExecution execution = jobExplorer.getJobExecution(jobExecutionId.longValue());
   logger.debug("Found execution: " + execution);
   return execution == null ? null : execution.getStartTime();
 }
 /**
  * Un-subscribes a customer from this plan, removing all plan item prices from the customer price
  * map.
  *
  * @param userId user id of the customer to un-subscribe
  */
 public void unsubscribe(Integer userId) {
   LOG.debug("Un-subscribing customer %s from plan %s", userId, plan.getId());
   new CustomerPriceBL(userId).removePrices(plan.getId());
 }