@Transactional
  @Override
  public EntityIdentifier adjustLoanTransaction(final AdjustLoanTransactionCommand command) {

    context.authenticatedUser();

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

    Loan loan = this.loanRepository.findOne(command.getLoanId());
    if (loan == null) {
      throw new LoanNotFoundException(command.getLoanId());
    }

    LoanTransaction transactionToAdjust =
        this.loanTransactionRepository.findOne(command.getTransactionId());
    if (transactionToAdjust == null) {
      throw new LoanTransactionNotFoundException(command.getTransactionId());
    }

    final MonetaryCurrency currency = loan.repaymentScheduleDetail().getPrincipal().getCurrency();
    final Money transactionAmount = Money.of(currency, command.getTransactionAmount());

    // adjustment is only supported for repayments and waivers at present
    LocalDate transactionDate = command.getTransactionDate();
    LoanTransaction newTransactionDetail =
        LoanTransaction.repayment(transactionAmount, transactionDate);
    if (transactionToAdjust.isInterestWaiver()) {
      newTransactionDetail = LoanTransaction.waiver(loan, transactionAmount, transactionDate);
    }

    loan.adjustExistingTransaction(
        transactionToAdjust, newTransactionDetail, defaultLoanLifecycleStateMachine());

    if (newTransactionDetail.isGreaterThanZero(currency)) {
      this.loanTransactionRepository.save(newTransactionDetail);
    }

    this.loanRepository.save(loan);

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

    return new EntityIdentifier(loan.getId());
  }
  @Transactional
  @Override
  public EntityIdentifier makeLoanRepayment(final LoanTransactionCommand command) {

    AppUser currentUser = context.authenticatedUser();

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

    Loan loan = this.loanRepository.findOne(command.getLoanId());
    if (loan == null) {
      throw new LoanNotFoundException(command.getLoanId());
    }

    LocalDate transactionDate = command.getTransactionDate();
    if (this.isBeforeToday(transactionDate) && currentUser.canNotMakeRepaymentOnLoanInPast()) {
      throw new NoAuthorizationException(
          "error.msg.no.permission.to.make.repayment.on.loan.in.past");
    }

    Money repayment =
        Money.of(
            loan.repaymentScheduleDetail().getPrincipal().getCurrency(),
            command.getTransactionAmount());

    LoanTransaction loanRepayment = LoanTransaction.repayment(repayment, transactionDate);
    loan.makeRepayment(loanRepayment, defaultLoanLifecycleStateMachine());
    this.loanTransactionRepository.save(loanRepayment);
    this.loanRepository.save(loan);

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

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