public EndOfDayBalance toEndOfDayBalanceBoundedBy( final Money openingBalance, final LocalDateInterval boundedBy) { MonetaryCurrency currency = openingBalance.getCurrency(); Money endOfDayBalance = openingBalance.copy(); int numberOfDaysOfBalance = this.balanceNumberOfDays; LocalDate balanceStartDate = getTransactionLocalDate(); LocalDate balanceEndDate = getEndOfBalanceLocalDate(); if (boundedBy.startDate().isAfter(balanceStartDate)) { balanceStartDate = boundedBy.startDate(); LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate); numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate(); } else { if (isDeposit()) { endOfDayBalance = openingBalance.plus(getAmount(currency)); } else if (isWithdrawal() || isWithdrawalFee()) { endOfDayBalance = openingBalance.minus(getAmount(currency)); } } if (balanceEndDate.isAfter(boundedBy.endDate())) { balanceEndDate = boundedBy.endDate(); LocalDateInterval spanOfBalance = LocalDateInterval.create(balanceStartDate, balanceEndDate); numberOfDaysOfBalance = spanOfBalance.daysInPeriodInclusiveOfEndDate(); } return EndOfDayBalance.from( balanceStartDate, openingBalance, endOfDayBalance, numberOfDaysOfBalance); }
public Money calculateTotalInterestWrittenOff( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency) { Money total = Money.zero(currency); for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) { total = total.plus(installment.getInterestWrittenOff(currency)); } return total; }
public Money calculateTotalPrincipalRepaid( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency) { Money total = Money.zero(currency); for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) { total = total.plus(installment.getPrincipalCompleted(currency)); } return total; }
public Money calculateTotalPenaltyChargesWaived( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency) { Money total = Money.zero(currency); for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) { total = total.plus(installment.getPenaltyChargesWaived(currency)); } return total; }
public Money calculateTotalInterestOverdueOn( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency, final LocalDate overdueAsOf) { Money total = Money.zero(currency); for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) { if (installment.isOverdueOn(overdueAsOf)) { total = total.plus(installment.getInterestOutstanding(currency)); } } return total; }
public EndOfDayBalance toEndOfDayBalance(final Money openingBalance) { MonetaryCurrency currency = openingBalance.getCurrency(); Money endOfDayBalance = openingBalance.copy(); if (isDeposit()) { endOfDayBalance = openingBalance.plus(getAmount(currency)); } else if (isWithdrawal() || isWithdrawalFee()) { endOfDayBalance = openingBalance.minus(getAmount(currency)); } return EndOfDayBalance.from( getTransactionLocalDate(), openingBalance, endOfDayBalance, this.balanceNumberOfDays); }
public LoanRepaymentScheduleInstallment fetchRepaymentInstallment(final Money trasferedAmount) { for (final LoanInstallmentCharge loanChargePerInstallment : this.loanInstallmentCharge) { if (loanChargePerInstallment.isPending() && trasferedAmount .getAmount() .equals( loanChargePerInstallment .getAmountThroughChargePayment(trasferedAmount.getCurrency()) .getAmount())) { return loanChargePerInstallment.getRepaymentInstallment(); } } return null; }
public void updateCumulativeBalanceAndDates( final MonetaryCurrency currency, final LocalDate endOfBalanceDate) { this.balanceEndDate = endOfBalanceDate.toDate(); this.balanceNumberOfDays = LocalDateInterval.create(getTransactionLocalDate(), endOfBalanceDate) .daysInPeriodInclusiveOfEndDate(); this.cumulativeBalance = Money.of(currency, this.runningBalance).multipliedBy(this.balanceNumberOfDays).getAmount(); }
public Money calculateTotalOverdueOn( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency, final LocalDate overdueAsOf) { final Money principalOverdue = calculateTotalPrincipalOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf); final Money interestOverdue = calculateTotalInterestOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf); final Money feeChargesOverdue = calculateTotalFeeChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf); final Money penaltyChargesOverdue = calculateTotalPenaltyChargesOverdueOn(repaymentScheduleInstallments, currency, overdueAsOf); return principalOverdue .plus(interestOverdue) .plus(feeChargesOverdue) .plus(penaltyChargesOverdue); }
public void updateSummary( final MonetaryCurrency currency, final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper) { this.totalPrincipalOverdue = summaryWrapper .calculateTotalPrincipalOverdueOn( repaymentScheduleInstallments, currency, DateUtils.getLocalDateOfTenant()) .getAmount(); this.totalInterestOverdue = summaryWrapper .calculateTotalInterestOverdueOn( repaymentScheduleInstallments, currency, DateUtils.getLocalDateOfTenant()) .getAmount(); this.totalFeeChargesOverdue = summaryWrapper .calculateTotalFeeChargesOverdueOn( repaymentScheduleInstallments, currency, DateUtils.getLocalDateOfTenant()) .getAmount(); this.totalPenaltyChargesOverdue = summaryWrapper .calculateTotalPenaltyChargesOverdueOn( repaymentScheduleInstallments, currency, DateUtils.getLocalDateOfTenant()) .getAmount(); final Money totalOverdue = Money.of(currency, this.totalPrincipalOverdue) .plus(this.totalInterestOverdue) .plus(this.totalFeeChargesOverdue) .plus(this.totalPenaltyChargesOverdue); this.totalOverdue = totalOverdue.getAmount(); final LocalDate overdueSinceLocalDate = summaryWrapper.determineOverdueSinceDateFrom( repaymentScheduleInstallments, currency, DateUtils.getLocalDateOfTenant()); if (overdueSinceLocalDate != null) { this.overdueSinceDate = overdueSinceLocalDate.toDate(); } else { this.overdueSinceDate = null; } }
public EndOfDayBalance toEndOfDayBalance( final Money openingBalance, final LocalDate nextTransactionDate) { MonetaryCurrency currency = openingBalance.getCurrency(); Money endOfDayBalance = openingBalance.copy(); if (isDeposit()) { endOfDayBalance = openingBalance.plus(getAmount(currency)); } else if (isWithdrawal() || isWithdrawalFee()) { endOfDayBalance = openingBalance.minus(getAmount(currency)); } int numberOfDays = LocalDateInterval.create(getTransactionLocalDate(), nextTransactionDate) .daysInPeriodInclusiveOfEndDate(); if (!openingBalance.isEqualTo(endOfDayBalance) && numberOfDays > 1) { numberOfDays = numberOfDays - 1; } return EndOfDayBalance.from( getTransactionLocalDate(), openingBalance, endOfDayBalance, numberOfDays); }
public LocalDate determineOverdueSinceDateFrom( final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final MonetaryCurrency currency, final LocalDate from) { LocalDate overdueSince = null; final Money totalOverdue = calculateTotalOverdueOn(repaymentScheduleInstallments, currency, from); if (totalOverdue.isGreaterThanZero()) { for (LoanRepaymentScheduleInstallment installment : repaymentScheduleInstallments) { if (installment.isOverdueOn(from)) { if (overdueSince == null || overdueSince.isAfter(installment.getDueDate())) { overdueSince = installment.getDueDate(); } } } } return overdueSince; }
private SavingsAccountTransaction( final SavingsAccount savingsAccount, final Integer typeOf, final LocalDate dateOf, final Money amount, final boolean isReversed) { this.savingsAccount = savingsAccount; this.typeOf = typeOf; this.dateOf = dateOf.toDate(); this.amount = amount.getAmount(); this.reversed = isReversed; }
public Money waive(final MonetaryCurrency currency, final Integer loanInstallmentNumber) { if (isInstalmentFee()) { final LoanInstallmentCharge chargePerInstallment = getInstallmentLoanCharge(loanInstallmentNumber); final Money amountWaived = chargePerInstallment.waive(currency); if (this.amountWaived == null) { this.amountWaived = BigDecimal.ZERO; } this.amountWaived = this.amountWaived.add(amountWaived.getAmount()); this.amountOutstanding = this.amountOutstanding.subtract(amountWaived.getAmount()); if (determineIfFullyPaid()) { this.paid = false; this.waived = true; } return amountWaived; } this.amountWaived = this.amountOutstanding; this.amountOutstanding = BigDecimal.ZERO; this.paid = false; this.waived = true; return getAmountWaived(currency); }
private SavingsAccountTransaction( final SavingsAccount savingsAccount, final PaymentDetail paymentDetail, final Integer typeOf, final LocalDate transactionLocalDate, final Money amount, final boolean isReversed) { this.savingsAccount = savingsAccount; this.typeOf = typeOf; this.dateOf = transactionLocalDate.toDate(); this.amount = amount.getAmount(); this.reversed = isReversed; this.paymentDetail = paymentDetail; }
@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 CommandProcessingResult officeTransaction(final JsonCommand command) { context.authenticatedUser(); this.moneyTransferCommandFromApiJsonDeserializer.validateOfficeTransfer(command.json()); Long officeId = null; Office fromOffice = null; final Long fromOfficeId = command.longValueOfParameterNamed("fromOfficeId"); if (fromOfficeId != null) { fromOffice = this.officeRepository.findOne(fromOfficeId); officeId = fromOffice.getId(); } Office toOffice = null; final Long toOfficeId = command.longValueOfParameterNamed("toOfficeId"); if (toOfficeId != null) { toOffice = this.officeRepository.findOne(toOfficeId); officeId = toOffice.getId(); } if (fromOffice == null && toOffice == null) { throw new OfficeNotFoundException(toOfficeId); } final String currencyCode = command.stringValueOfParameterNamed("currencyCode"); final ApplicationCurrency appCurrency = this.applicationCurrencyRepository.findOneByCode(currencyCode); if (appCurrency == null) { throw new CurrencyNotFoundException(currencyCode); } final MonetaryCurrency currency = new MonetaryCurrency(appCurrency.getCode(), appCurrency.getDecimalPlaces()); final Money amount = Money.of(currency, command.bigDecimalValueOfParameterNamed("transactionAmount")); final OfficeTransaction entity = OfficeTransaction.fromJson(fromOffice, toOffice, amount, command); this.officeTransactionRepository.save(entity); return new CommandProcessingResultBuilder() // .withCommandId(command.commandId()) // .withEntityId(entity.getId()) // .withOfficeId(officeId) // .build(); }
@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()); }
public EndOfDayBalance toEndOfDayBalance( final LocalDateInterval periodInterval, final MonetaryCurrency currency) { Money endOfDayBalance = Money.of(currency, this.runningBalance); Money openingBalance = endOfDayBalance; LocalDate balanceDate = periodInterval.startDate(); int numberOfDays = periodInterval.daysInPeriodInclusiveOfEndDate(); if (periodInterval.contains(getTransactionLocalDate())) { balanceDate = getTransactionLocalDate(); LocalDateInterval newInterval = LocalDateInterval.create(getTransactionLocalDate(), periodInterval.endDate()); numberOfDays = newInterval.daysInPeriodInclusiveOfEndDate(); } return EndOfDayBalance.from(balanceDate, openingBalance, endOfDayBalance, numberOfDays); }
@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()); }
/** * @param percentageOf * @returns a minimum cap or maximum cap set on charges if the criteria fits else it returns the * percentageOf if the amount is within min and max cap */ private BigDecimal minimumAndMaximumCap(final BigDecimal percentageOf) { BigDecimal minMaxCap = BigDecimal.ZERO; if (this.minCap != null) { final int minimumCap = percentageOf.compareTo(this.minCap); if (minimumCap == -1) { minMaxCap = this.minCap; return minMaxCap; } } if (this.maxCap != null) { final int maximumCap = percentageOf.compareTo(this.maxCap); if (maximumCap == 1) { minMaxCap = this.maxCap; return minMaxCap; } } minMaxCap = percentageOf; // this will round the amount value if (this.loan != null && minMaxCap != null) { minMaxCap = Money.of(this.loan.getCurrency(), minMaxCap).getAmount(); } return minMaxCap; }
public Money getTotalFeeChargesDueAtDisbursement(final MonetaryCurrency currency) { return Money.of(currency, this.totalFeeChargesDueAtDisbursement); }
public boolean hasNotAmount(final Money amountToCheck) { final Money transactionAmount = getAmount(amountToCheck.getCurrency()); return transactionAmount.isNotEqualTo(amountToCheck); }
public void updateRunningBalance(final Money balance) { this.runningBalance = balance.getAmount(); }
public Money getAmount(final MonetaryCurrency currency) { return Money.of(currency, this.amount); }
public boolean isNotInArrears(final MonetaryCurrency currency) { return Money.of(currency, this.totalOverdue).isZero(); }
public void updateSummary( final MonetaryCurrency currency, final Money principal, final List<LoanRepaymentScheduleInstallment> repaymentScheduleInstallments, final LoanSummaryWrapper summaryWrapper, final Boolean disbursed) { this.totalPrincipalDisbursed = principal.getAmount(); this.totalPrincipalRepaid = summaryWrapper .calculateTotalPrincipalRepaid(repaymentScheduleInstallments, currency) .getAmount(); this.totalPrincipalWrittenOff = summaryWrapper .calculateTotalPrincipalWrittenOff(repaymentScheduleInstallments, currency) .getAmount(); this.totalPrincipalOutstanding = principal.minus(this.totalPrincipalRepaid).minus(this.totalPrincipalWrittenOff).getAmount(); final Money totalInterestCharged = summaryWrapper.calculateTotalInterestCharged(repaymentScheduleInstallments, currency); this.totalInterestCharged = totalInterestCharged.getAmount(); this.totalInterestRepaid = summaryWrapper .calculateTotalInterestRepaid(repaymentScheduleInstallments, currency) .getAmount(); this.totalInterestWaived = summaryWrapper .calculateTotalInterestWaived(repaymentScheduleInstallments, currency) .getAmount(); this.totalInterestWrittenOff = summaryWrapper .calculateTotalInterestWrittenOff(repaymentScheduleInstallments, currency) .getAmount(); this.totalInterestOutstanding = totalInterestCharged .minus(this.totalInterestRepaid) .minus(this.totalInterestWaived) .minus(this.totalInterestWrittenOff) .getAmount(); final Money totalFeeChargesCharged = summaryWrapper .calculateTotalFeeChargesCharged(repaymentScheduleInstallments, currency) .plus(this.totalFeeChargesDueAtDisbursement); this.totalFeeChargesCharged = totalFeeChargesCharged.getAmount(); Money totalFeeChargesRepaid = summaryWrapper.calculateTotalFeeChargesRepaid(repaymentScheduleInstallments, currency); if (disbursed) { totalFeeChargesRepaid = totalFeeChargesRepaid.plus(this.totalFeeChargesDueAtDisbursement); } this.totalFeeChargesRepaid = totalFeeChargesRepaid.getAmount(); this.totalFeeChargesWaived = summaryWrapper .calculateTotalFeeChargesWaived(repaymentScheduleInstallments, currency) .getAmount(); this.totalFeeChargesWrittenOff = summaryWrapper .calculateTotalFeeChargesWrittenOff(repaymentScheduleInstallments, currency) .getAmount(); this.totalFeeChargesOutstanding = totalFeeChargesCharged .minus(this.totalFeeChargesRepaid) .minus(this.totalFeeChargesWaived) .minus(this.totalFeeChargesWrittenOff) .getAmount(); final Money totalPenaltyChargesCharged = summaryWrapper.calculateTotalPenaltyChargesCharged(repaymentScheduleInstallments, currency); this.totalPenaltyChargesCharged = totalPenaltyChargesCharged.getAmount(); this.totalPenaltyChargesRepaid = summaryWrapper .calculateTotalPenaltyChargesRepaid(repaymentScheduleInstallments, currency) .getAmount(); this.totalPenaltyChargesWaived = summaryWrapper .calculateTotalPenaltyChargesWaived(repaymentScheduleInstallments, currency) .getAmount(); this.totalPenaltyChargesWrittenOff = summaryWrapper .calculateTotalPenaltyChargesWrittenOff(repaymentScheduleInstallments, currency) .getAmount(); this.totalPenaltyChargesOutstanding = totalPenaltyChargesCharged .minus(this.totalPenaltyChargesRepaid) .minus(this.totalPenaltyChargesWaived) .minus(this.totalPenaltyChargesWrittenOff) .getAmount(); final Money totalExpectedRepayment = Money.of(currency, this.totalPrincipalDisbursed) .plus(this.totalInterestCharged) .plus(this.totalFeeChargesCharged) .plus(this.totalPenaltyChargesCharged); this.totalExpectedRepayment = totalExpectedRepayment.getAmount(); final Money totalRepayment = Money.of(currency, this.totalPrincipalRepaid) .plus(this.totalInterestRepaid) .plus(this.totalFeeChargesRepaid) .plus(this.totalPenaltyChargesRepaid); this.totalRepayment = totalRepayment.getAmount(); final Money totalExpectedCostOfLoan = Money.of(currency, this.totalInterestCharged) .plus(this.totalFeeChargesCharged) .plus(this.totalPenaltyChargesCharged); this.totalExpectedCostOfLoan = totalExpectedCostOfLoan.getAmount(); final Money totalCostOfLoan = Money.of(currency, this.totalInterestRepaid) .plus(this.totalFeeChargesRepaid) .plus(this.totalPenaltyChargesRepaid); this.totalCostOfLoan = totalCostOfLoan.getAmount(); final Money totalWaived = Money.of(currency, this.totalInterestWaived) .plus(this.totalFeeChargesWaived) .plus(this.totalPenaltyChargesWaived); this.totalWaived = totalWaived.getAmount(); final Money totalWrittenOff = Money.of(currency, this.totalPrincipalWrittenOff) .plus(this.totalInterestWrittenOff) .plus(this.totalFeeChargesWrittenOff) .plus(this.totalPenaltyChargesWrittenOff); this.totalWrittenOff = totalWrittenOff.getAmount(); final Money totalOutstanding = Money.of(currency, this.totalPrincipalOutstanding) .plus(this.totalInterestOutstanding) .plus(this.totalFeeChargesOutstanding) .plus(this.totalPenaltyChargesOutstanding); this.totalOutstanding = totalOutstanding.getAmount(); }
@Transactional @Override public LoanTransaction makeRepayment( final Long accountId, final CommandProcessingResultBuilder builderResult, final LocalDate transactionDate, final BigDecimal transactionAmount, final PaymentDetail paymentDetail, final String noteText, final String txnExternalId) { final Loan loan = this.loanAccountAssembler.assembleFrom(accountId); checkClientOrGroupActive(loan); // TODO: Is it required to validate transaction date with meeting dates // if repayments is synced with meeting? /* * if(loan.isSyncDisbursementWithMeeting()){ // validate actual * disbursement date against meeting date CalendarInstance * calendarInstance = * this.calendarInstanceRepository.findCalendarInstaneByLoanId * (loan.getId(), CalendarEntityType.LOANS.getValue()); * this.loanEventApiJsonValidator * .validateRepaymentDateWithMeetingDate(transactionDate, * calendarInstance); } */ final List<Long> existingTransactionIds = new ArrayList<Long>(); final List<Long> existingReversedTransactionIds = new ArrayList<Long>(); final Money repaymentAmount = Money.of(loan.getCurrency(), transactionAmount); final LoanTransaction newRepaymentTransaction = LoanTransaction.repayment(repaymentAmount, paymentDetail, transactionDate, txnExternalId); final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled(); final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate( loan.getOfficeId(), transactionDate.toDate()); final WorkingDays workingDays = this.workingDaysRepository.findOne(); final boolean allowTransactionsOnNonWorkingDay = this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled(); final ChangedTransactionDetail changedTransactionDetail = loan.makeRepayment( newRepaymentTransaction, defaultLoanLifecycleStateMachine(), existingTransactionIds, existingReversedTransactionIds, allowTransactionsOnHoliday, holidays, workingDays, allowTransactionsOnNonWorkingDay); this.loanTransactionRepository.save(newRepaymentTransaction); /** * * TODO Vishwas Batch save is giving me a HibernateOptimisticLockingFailureException, looping * and saving for the time being, not a major issue for now as this loop is entered only in edge * cases (when a payment is made before the latest payment recorded against the loan) * */ if (changedTransactionDetail != null) { for (final LoanTransaction loanTransaction : changedTransactionDetail.getNewTransactions()) { this.loanTransactionRepository.save(loanTransaction); } } this.loanRepository.save(loan); if (StringUtils.isNotBlank(noteText)) { final Note note = Note.loanTransactionNote(loan, newRepaymentTransaction, noteText); this.noteRepository.save(note); } postJournalEntries(loan, existingTransactionIds, existingReversedTransactionIds); builderResult .withEntityId(newRepaymentTransaction.getId()) // .withOfficeId(loan.getOfficeId()) // .withClientId(loan.getClientId()) // .withGroupId(loan.getGroupId()); // return newRepaymentTransaction; }
private LoanApplicationTerms assembleLoanApplicationTermsFrom( final JsonElement element, final LoanProduct loanProduct) { final MonetaryCurrency currency = loanProduct.getCurrency(); final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency); // loan terms final Integer loanTermFrequency = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequency", element); final Integer loanTermFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("loanTermFrequencyType", element); final PeriodFrequencyType loanTermPeriodFrequencyType = PeriodFrequencyType.fromInt(loanTermFrequencyType); final Integer numberOfRepayments = fromApiJsonHelper.extractIntegerWithLocaleNamed("numberOfRepayments", element); final Integer repaymentEvery = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentEvery", element); final Integer repaymentFrequencyType = fromApiJsonHelper.extractIntegerWithLocaleNamed("repaymentFrequencyType", element); final PeriodFrequencyType repaymentPeriodFrequencyType = PeriodFrequencyType.fromInt(repaymentFrequencyType); final Integer amortizationType = fromApiJsonHelper.extractIntegerWithLocaleNamed("amortizationType", element); final AmortizationMethod amortizationMethod = AmortizationMethod.fromInt(amortizationType); // interest terms final Integer interestType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestType", element); final InterestMethod interestMethod = InterestMethod.fromInt(interestType); final Integer interestCalculationPeriodType = fromApiJsonHelper.extractIntegerWithLocaleNamed("interestCalculationPeriodType", element); final InterestCalculationPeriodMethod interestCalculationPeriodMethod = InterestCalculationPeriodMethod.fromInt(interestCalculationPeriodType); final BigDecimal interestRatePerPeriod = fromApiJsonHelper.extractBigDecimalWithLocaleNamed("interestRatePerPeriod", element); final PeriodFrequencyType interestRatePeriodFrequencyType = loanProduct.getInterestPeriodFrequencyType(); final BigDecimal annualNominalInterestRate = this.aprCalculator.calculateFrom(interestRatePeriodFrequencyType, interestRatePerPeriod); // disbursement details final BigDecimal principal = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("principal", element); final Money principalMoney = Money.of(currency, principal); final LocalDate expectedDisbursementDate = this.fromApiJsonHelper.extractLocalDateNamed("expectedDisbursementDate", element); final LocalDate repaymentsStartingFromDate = this.fromApiJsonHelper.extractLocalDateNamed("repaymentsStartingFromDate", element); LocalDate calculatedRepaymentsStartingFromDate = repaymentsStartingFromDate; final Boolean synchDisbursement = fromApiJsonHelper.extractBooleanNamed("syncDisbursementWithMeeting", element); final Long calendarId = this.fromApiJsonHelper.extractLongNamed("calendarId", element); Calendar calendar = null; if ((synchDisbursement != null && synchDisbursement.booleanValue()) || (calendarId != null && calendarId != 0)) { calendar = this.calendarRepository.findOne(calendarId); if (calendar == null) { throw new CalendarNotFoundException(calendarId); } // validate repayment frequency and interval with meeting frequency and interval PeriodFrequencyType meetingPeriodFrequency = CalendarHelper.getMeetingPeriodFrequencyType(calendar.getRecurrence()); validateRepaymentFrequencyIsSameAsMeetingFrequency( meetingPeriodFrequency.getValue(), repaymentFrequencyType, CalendarHelper.getInterval(calendar.getRecurrence()), repaymentEvery); } if (synchDisbursement != null && synchDisbursement.booleanValue()) { validateDisbursementDateWithMeetingDates(expectedDisbursementDate, calendar); } // if calendar is attached (not null) then reschedule repayment dates according to meeting if (null != calendar) { // TODO : AA - Is it require to reset repaymentsStartingFromDate or // set only if it is not provided (or null) // Currently provided repaymentsStartingFromDate takes precedence over system generated next // meeting date if (calculatedRepaymentsStartingFromDate == null) { // FIXME: AA - Possibility of having next meeting date immediately after disbursement date, // need to have minimum number of days gap between disbursement and first repayment date. final String frequency = CalendarHelper.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType); calculatedRepaymentsStartingFromDate = CalendarHelper.getFirstRepaymentMeetingDate( calendar, expectedDisbursementDate, repaymentEvery, frequency); } else { // validate user provided repaymentsStartFromDate validateRepaymentsStartDateWithMeetingDates(repaymentsStartingFromDate, calendar); } } // grace details final Integer graceOnPrincipalPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnPrincipalPayment", element); final Integer graceOnInterestPayment = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestPayment", element); final Integer graceOnInterestCharged = this.fromApiJsonHelper.extractIntegerWithLocaleNamed("graceOnInterestCharged", element); final LocalDate interestChargedFromDate = fromApiJsonHelper.extractLocalDateNamed("interestChargedFromDate", element); // other final BigDecimal inArrearsTolerance = this.fromApiJsonHelper.extractBigDecimalWithLocaleNamed("inArrearsTolerance", element); final Money inArrearsToleranceMoney = Money.of(currency, inArrearsTolerance); return LoanApplicationTerms.assembleFrom( applicationCurrency, loanTermFrequency, loanTermPeriodFrequencyType, numberOfRepayments, repaymentEvery, repaymentPeriodFrequencyType, amortizationMethod, interestMethod, interestRatePerPeriod, interestRatePeriodFrequencyType, annualNominalInterestRate, interestCalculationPeriodMethod, principalMoney, expectedDisbursementDate, repaymentsStartingFromDate, calculatedRepaymentsStartingFromDate, graceOnPrincipalPayment, graceOnInterestPayment, graceOnInterestCharged, interestChargedFromDate, inArrearsToleranceMoney); }
public Money getTotalOutstanding(final MonetaryCurrency currency) { return Money.of(currency, this.totalOutstanding); }