@Override
  public EntityIdentifier updateDepositAccount(DepositAccountCommand command) {

    try {
      this.context.authenticatedUser();

      DepositAccountCommandValidator validator = new DepositAccountCommandValidator(command);
      validator.validateForUpdate();

      final DepositAccount account = this.depositAccountRepository.findOne(command.getId());
      if (account == null || account.isDeleted()) {
        throw new DepositAccountNotFoundException(command.getId());
      }

      if (account.isSubmittedAndPendingApproval()) {
        this.depositAccountAssembler.assembleUpdatedDepositAccount(account, command);
      } else if (account.isActive()) {
        this.depositAccountAssembler.updateApprovedDepositAccount(account, command);
      }

      this.depositAccountRepository.save(account);

      return new EntityIdentifier(account.getId());
    } catch (DataIntegrityViolationException dve) {
      handleDataIntegrityIssues(command, dve);
      return new EntityIdentifier(Long.valueOf(-1));
    }
  }
  @Transactional
  @Override
  public EntityIdentifier renewDepositAccount(DepositAccountCommand command) {

    this.context.authenticatedUser();

    RenewDepositAccountCommandValidator validator =
        new RenewDepositAccountCommandValidator(command);
    validator.validateForCreate();

    DepositAccount account = this.depositAccountRepository.findOne(command.getId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getId());
    }

    // FIXME - KW - extract whats in this if into a method that naturally
    // describes what you are checking.
    if (account.isRenewalAllowed()
        && (new LocalDate().isAfter(account.maturesOnDate())
            || new LocalDate().isEqual(account.maturesOnDate()))) {

      if (account.isActive()) {
        final DepositAccount renewedAccount =
            this.depositAccountAssembler.assembleFrom(account, command);
        this.depositAccountRepository.save(renewedAccount);
        account.closeDepositAccount(defaultDepositLifecycleStateMachine());
        this.depositAccountRepository.save(account);
        return new EntityIdentifier(renewedAccount.getId());
      }

      throw new DepositAccountReopenException(account.getMaturityDate());
    }

    throw new DepositAccountReopenException(account.getMaturityDate());
  }
  @Transactional
  @Override
  public EntityIdentifier deleteDepositAccount(final Long accountId) {

    this.context.authenticatedUser();

    DepositAccount account = this.depositAccountRepository.findOne(accountId);
    if (account == null || account.isDeleted()) {
      throw new SavingsProductNotFoundException(accountId);
    }

    account.delete();
    this.depositAccountRepository.save(account);

    return new EntityIdentifier(accountId);
  }
  @Transactional
  @Override
  public EntityIdentifier withdrawDepositAccountInterestMoney(
      DepositAccountWithdrawInterestCommand command) {

    context.authenticatedUser();

    WithDrawDepositAccountInterestCommandValidator validator =
        new WithDrawDepositAccountInterestCommandValidator(command);
    validator.validate();

    DepositAccount account = this.depositAccountRepository.findOne(command.getAccountId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getAccountId());
    }
    if (account.isInterestWithdrawable() && !account.isInterestCompoundingAllowed()) {

      // BigDecimal totalAvailableInterestForWithdrawal =
      // getTotalWithdrawableInterestAvailable(account);
      // BigDecimal interestPaid = account.getInterstPaid();
      BigDecimal remainInterestForWithdrawal =
          account
              .getAvailableInterest(); // totalAvailableInterestForWithdrawal.subtract(interestPaid);

      if (remainInterestForWithdrawal.doubleValue() > 0) {
        if (remainInterestForWithdrawal.doubleValue() >= command.getWithdrawInterest().doubleValue()
            && command.getWithdrawInterest().doubleValue() > 0) {
          account.withdrawInterest(
              Money.of(account.getDeposit().getCurrency(), command.getWithdrawInterest()));
          this.depositAccountRepository.save(account);
        } else {
          throw new DepositAccountTransactionsException(
              "deposit.transaction.interest.withdrawal.exceed",
              "You can Withdraw " + remainInterestForWithdrawal + " only");
        }
      } else {
        throw new DepositAccountTransactionsException(
            "deposit.transaction.interest.withdrawal.insufficient.amount",
            "You don't have enough money for withdrawal");
      }
    } else {
      throw new DepositAccountTransactionsException(
          "deposit.transaction.interest.withdrawal.cannot.withdraw",
          "You can not withdraw interst for this account");
    }
    return new EntityIdentifier(account.getId());
  }
  @Transactional
  @Override
  public EntityIdentifier approveDepositApplication(
      final DepositStateTransitionApprovalCommand command) {

    // AppUser currentUser = context.authenticatedUser();

    DepositStateTransitionApprovalCommandValidator validator =
        new DepositStateTransitionApprovalCommandValidator(command);
    validator.validate();

    DepositAccount account = this.depositAccountRepository.findOne(command.getAccountId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getAccountId());
    }

    // FIXME - madhukar - you are checking for loan permission here instead
    // of some specific deposit account permission.
    // removing check for now until rules dealing with creating and
    // maintaining deposit accounts in the past is clarified
    LocalDate eventDate = command.getEventDate();
    // if (this.isBeforeToday(eventDate) &&
    // currentUser.canNotApproveLoanInPast()) {
    // throw new
    // NoAuthorizationException("User has no authority to approve deposit with a date in the
    // past.");
    // }

    account.approve(
        eventDate,
        defaultDepositLifecycleStateMachine(),
        command,
        this.fixedTermDepositInterestCalculator);

    this.depositAccountRepository.save(account);

    String noteText = command.getNote();
    if (StringUtils.isNotBlank(noteText)) {
      Note note = Note.depositNote(account, noteText);
      this.noteRepository.save(note);
    }

    return new EntityIdentifier(account.getId());
  }
  @Transactional
  @Override
  public EntityIdentifier withdrawDepositAccountMoney(
      final DepositAccountWithdrawalCommand command) {

    context.authenticatedUser();

    DepositAccountWithdrawalCommandValidator validator =
        new DepositAccountWithdrawalCommandValidator(command);
    validator.validate();

    DepositAccount account = this.depositAccountRepository.findOne(command.getAccountId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getAccountId());
    }

    LocalDate eventDate = command.getMaturesOnDate();

    Integer lockinPeriod = account.getLockinPeriod();
    LocalDate lockinPeriodExpDate =
        account.getActualCommencementDate().plusMonths(Integer.valueOf(lockinPeriod));
    if (account.isLockinPeriodAllowed()) {
      if (eventDate.isBefore(lockinPeriodExpDate)) {
        throw new DepositAccountTransactionsException(
            "deposit.transaction.canot.withdraw.before.lockinperiod.reached",
            "You can not withdraw your application before maturity date reached");
      }
    }
    // if (eventDate.isBefore(account.maturesOnDate())) {
    // this.depositAccountAssembler.adjustTotalAmountForPreclosureInterest(account,
    // eventDate);
    // }
    account.withdrawDepositAccountMoney(
        defaultDepositLifecycleStateMachine(), fixedTermDepositInterestCalculator, eventDate);
    this.depositAccountRepository.save(account);
    String noteText = command.getNote();
    if (StringUtils.isNotBlank(noteText)) {
      Note note = Note.depositNote(account, noteText);
      this.noteRepository.save(note);
    }

    return new EntityIdentifier(account.getId());
  }
  @Transactional
  @Override
  public EntityIdentifier postInterestToDepositAccount(
      Collection<DepositAccountsForLookup> accounts) {

    try {

      for (DepositAccountsForLookup accountData : accounts) {
        DepositAccount account = this.depositAccountRepository.findOne(accountData.getId());
        if (account == null || account.isDeleted()) {
          throw new DepositAccountNotFoundException(accountData.getId());
        }
        this.depositAccountAssembler.postInterest(account);
        this.depositAccountRepository.save(account);
      }
      return new EntityIdentifier(new Long(accounts.size()));
    } catch (Exception e) {
      return new EntityIdentifier(Long.valueOf(-1));
    }
  }
  @Transactional
  @Override
  public EntityIdentifier undoDepositApproval(UndoStateTransitionCommand command) {

    context.authenticatedUser();

    DepositAccount account = this.depositAccountRepository.findOne(command.getLoanId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getLoanId());
    }

    account.undoDepositApproval(defaultDepositLifecycleStateMachine());
    this.depositAccountRepository.save(account);

    String noteText = command.getNote();
    if (StringUtils.isNotBlank(noteText)) {
      Note note = Note.depositNote(account, noteText);
      this.noteRepository.save(note);
    }
    return new EntityIdentifier(account.getId());
  }
  @Transactional
  @Override
  public EntityIdentifier withdrawDepositApplication(DepositStateTransitionCommand command) {

    // AppUser currentUser = context.authenticatedUser();

    DepositStateTransitionCommandValidator validator =
        new DepositStateTransitionCommandValidator(command);
    validator.validate();

    DepositAccount account = this.depositAccountRepository.findOne(command.getAccountId());
    if (account == null || account.isDeleted()) {
      throw new DepositAccountNotFoundException(command.getAccountId());
    }

    // removing check for now until rules dealing with creating and
    // maintaining deposit accounts in the past is clarified
    LocalDate eventDate = command.getEventDate();
    // if (this.isBeforeToday(eventDate) &&
    // currentUser.canNotApproveLoanInPast()) {
    // throw new
    // NoAuthorizationException("User has no authority to approve deposit with a date in the
    // past.");
    // }

    account.withdrawnByApplicant(eventDate, defaultDepositLifecycleStateMachine());
    this.depositAccountRepository.save(account);

    String noteText = command.getNote();
    if (StringUtils.isNotBlank(noteText)) {
      Note note = Note.depositNote(account, noteText);
      this.noteRepository.save(note);
    }

    return new EntityIdentifier(account.getId());
  }