blob: 418ac8999f8b22aa7644f706b504ce9b43363907 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.portfolio.loanaccount;
import java.lang.reflect.Field;
import java.math.RoundingMode;
import java.util.List;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
import org.joda.time.LocalDate;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.runners.MockitoJUnitRunner;
@SuppressWarnings("unused")
@RunWith(MockitoJUnitRunner.class)
public class HeavensFamilyLoanRepaymentScheduleTransactionProcessorTest {
// class under test
private HeavensFamilyLoanRepaymentScheduleTransactionProcessor processor;
//
private final LocalDate july2nd = new LocalDate(2012, 7, 2);
private final MonetaryCurrency usDollars = new MonetaryCurrencyBuilder().withCode("USD").withDigitsAfterDecimal(2).build();
private List<LoanRepaymentScheduleInstallment> installments;
@Before
public void setUpForEachTestCase() throws Exception {
Field field = MoneyHelper.class.getDeclaredField("roundingMode");
field.setAccessible(true);
field.set(null, RoundingMode.HALF_EVEN);
this.installments = LoanScheduleTestDataHelper.createSimpleLoanSchedule(this.july2nd, this.usDollars);
this.processor = new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();
}
/**
* Scenario 1: Single transaction which is less than the interest component
* of the first installment.
*
* Expectation: - First installment shows interest completed equal to that
* of transactions, zero principal completed. (payment order interest,
* principal) - transaction has interest portion equal to transaction
* amount, and zero principal portion
*/
@Test
public void givenSingleOnTimeLoanTransactionShouldPayoffInterestComponentFirst() {
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money oneHundredDollars = new
// MoneyBuilder().with(usDollars).with("100.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(oneHundredDollars).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("0.00",
// "100.00", singleInstallment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("0.00",
// "100.00", onTimePartialPayment);
}
// /**
// * Scenario 2: Two transactions which is less than the interest component
// of the first installment.
// *
// * Expectation:
// * - First installment shows interest completed equal to that of
// transactions, zero principal completed. (payment order interest,
// principal)
// * - transactions has interest portion equal to transaction amount, and
// zero principal portion
// */
// @Test
// public void
// givenMultipleOnTimeLoanTransactionShouldPayoffInterestComponentFirst() {
//
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money oneHundredDollars = new
// MoneyBuilder().with(usDollars).with("100.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(oneHundredDollars).build();
//
// Money fiftyDollars = new
// MoneyBuilder().with(usDollars).with("50.00").build();
// LoanTransaction secondOnTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(fiftyDollars).build();
//
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
// processor.handleTransaction(secondOnTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("0.00",
// "150.00", singleInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("0.00",
// "100.00", onTimePartialPayment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("0.00",
// "50.00", secondOnTimePartialPayment);
// }
//
// /**
// * Scenario 3: Single transaction which is greater than the interest
// component of the first installment but less than the total due for
// installment.
// *
// * Expectation:
// * - First installment shows interest completed equal to that interest
// due, remainder is against principal completed. (payment order interest,
// principal)
// * - transaction has interest portion equal to interest expected and
// principal portion of remainder.
// */
// @Test
// public void
// givenSingleOnTimeLoanTransactionShouldPayoffInterestThenPrincipalComponents()
// {
//
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money amount = new MoneyBuilder().with(usDollars).with("300.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("100.00",
// "200.00", singleInstallment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("100.00",
// "200.00", onTimePartialPayment);
// }
//
// /**
// * Scenario 4: Single transaction which is greater than the interest
// component of the first installment but less than the total due for
// installment.
// *
// * Expectation:
// * - First installment shows interest completed equal to that interest
// due, remainder is against principal completed. (payment order interest,
// principal)
// * - transaction has interest portion equal to interest expected and
// principal portion of remainder.
// */
// @Test
// public void
// givenMultipleOnTimeLoanTransactionShouldPayoffInterestThenPrincipalComponents()
// {
//
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money amount = new MoneyBuilder().with(usDollars).with("300.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// Money secondTransactionAmount = new
// MoneyBuilder().with(usDollars).with("50.00").build();
// LoanTransaction secondOnTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(secondTransactionAmount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
// processor.handleTransaction(secondOnTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("150.00",
// "200.00", singleInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("100.00",
// "200.00", onTimePartialPayment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("50.00",
// "0.00", secondOnTimePartialPayment);
// }
//
// /**
// * Scenario 5:Single transaction which is equal to the total due for
// installment.
// *
// * Expectation:
// * - First installment shows interest completed and principal completed
// equal to their due amounts. (payment order interest, principal)
// * - transaction has interest portion and principal portions
// */
// @Test
// public void
// givenSingleFullOnTimeLoanTransactionShouldPayoffInterestThenPrincipalComponentInFull()
// {
//
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money amount = new
// MoneyBuilder().with(usDollars).with("1200.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("1000.00",
// "200.00", singleInstallment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("1000.00",
// "200.00", onTimePartialPayment);
// }
//
// /**
// * Scenario 6: Multiple transactions which together equal to the total due
// for installment.
// *
// * Expectation:
// * - First installment shows interest completed and principal completed
// equal to their due amounts. (payment order interest, principal)
// * - transaction has interest portion and principal portions
// */
// @Test
// public void
// givenMuliptleOnTimeLoanTransactionsThatInFullShouldPayoffInterestThenPrincipalComponentInFull()
// {
//
// // setup
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
//
// Money amount = new MoneyBuilder().with(usDollars).with("600.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// Money secondTransactionAmount = new
// MoneyBuilder().with(usDollars).with("600.00").build();
// LoanTransaction secondOnTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(secondTransactionAmount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
// processor.handleTransaction(secondOnTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("1000.00",
// "200.00", singleInstallment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("400.00",
// "200.00", onTimePartialPayment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("600.00",
// "0.00", secondOnTimePartialPayment);
// }
//
// /**
// * Scenario 7: Single transaction which is greater than total due for
// first installment.
// *
// * Expectation:
// * - First installment shows interest completed and principal completed
// equal to their due amounts. (payment order interest, principal)
// * - Second installment shows principal completed equal to the remaining
// amount
// * - transaction has interest portion and principal portions, the
// principal portion is the sum of principal completed for first and second
// installments
// */
// @Test
// public void
// givenSingleOnTimeLoanTransactionThatOverpaysInstallmentShouldPayoffInterestThenPrincipalComponentInFullOfFirstInstallmentWithRemainingOverpaymentAgainstPrincipalOfNextInstallment()
// {
//
// // setup
// Money amount = new
// MoneyBuilder().with(usDollars).with("1300.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// LoanRepaymentScheduleInstallment firstInstallment =
// this.installments.get(0);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("1000.00",
// "200.00", firstInstallment);
//
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("100.00",
// "0.00", secondInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("1100.00",
// "200.00", onTimePartialPayment);
// }
//
// /**
// * Scenario 8: Multiple transactions which together are greater than total
// due for first installment.
// *
// * Expectation:
// * - First installment shows interest completed and principal completed
// equal to their due amounts. (payment order interest, principal)
// * - Second installment shows principal completed equal to the remaining
// amount
// */
// @Test
// public void
// givenMultipleOnTimeLoanTransactionThatOverpaysInstallmentShouldPayoffInterestThenPrincipalComponentInFullOfFirstInstallmentWithRemainingOverpaymentAgainstPrincipalOfNextInstallment()
// {
//
// // setup
// Money amount = new MoneyBuilder().with(usDollars).with("600.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// Money secondTransactionAmount = new
// MoneyBuilder().with(usDollars).with("700.00").build();
// LoanTransaction secondOnTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(secondTransactionAmount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
// processor.handleTransaction(secondOnTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// LoanRepaymentScheduleInstallment singleInstallment =
// this.installments.get(0);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("1000.00",
// "200.00", singleInstallment);
//
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("100.00",
// "0.00", secondInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("400.00",
// "200.00", onTimePartialPayment);
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("700.00",
// "0.00", secondOnTimePartialPayment);
// }
//
// /**
// * Scenario 9: Single transaction which overpays first installment and
// second installment with outstanding amount been account as principal in
// third installment.
// *
// * Where an installments principal is paid for fully in advance - the
// interest component is waived.
// */
// @Test
// public void
// givenOverPaymentShouldPayoffInterestThenPrincipalComponentsOfFirstInstallmentWithRemainingOverpaymentAgainstPrincipalOfAllSubsequentInstallments()
// {
// // setup
// Money amount = new
// MoneyBuilder().with(usDollars).with("3000.00").build();
// LoanTransaction onTimePartialPayment = new
// LoanTransactionBuilder().repayment().with(july2nd).with(amount).build();
//
// // execute test
// processor.handleTransaction(onTimePartialPayment, usDollars,
// installments);
//
// // verification of derived fields on installments
// LoanRepaymentScheduleInstallment firstInstallment =
// this.installments.get(0);
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("1000.00"),
// interestOf("200.00"), interestWaivedOf("0.00"), firstInstallment,
// usDollars);
//
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("1000.00"),
// interestOf("0.00"), interestWaivedOf("200.00"), secondInstallment,
// usDollars);
//
// LoanRepaymentScheduleInstallment thirdInstallment =
// this.installments.get(2);
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("800.00"),
// interestOf("0.00"), interestWaivedOf("0.00"), thirdInstallment,
// usDollars);
//
// assertThatLoanTransactionHasDerivedFieldsOf(principalOf("2800.00"),
// interestOf("200.00"), onTimePartialPayment, usDollars);
// }
//
// /**
// * Scenario 10: Single transaction which is a repayment in advance
// */
// @Test
// public void
// givenRepaymentOfInstallmentInAdvanceShouldPayoffOnlyPrincipalComponent()
// {
// // setup
// installments =
// LoanScheduleTestDataHelper.createSimpleLoanScheduleWithFirstInstallmentFullyPaid(july2nd,
// usDollars);
// LoanRepaymentScheduleInstallment firstInstallment =
// this.installments.get(0);
// LocalDate paymentInAdvanceDate =
// firstInstallment.getDueDate().minusDays(1);
//
// Money amount = new MoneyBuilder().with(usDollars).with("900.00").build();
// LoanTransaction paymentInAdvance = new
// LoanTransactionBuilder().repayment().with(paymentInAdvanceDate).with(amount).build();
//
// // execute test
// processor.handleTransaction(paymentInAdvance, usDollars, installments);
//
// // verification of derived fields on installments
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("900.00",
// "0.00", secondInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("900.00",
// "0.00", paymentInAdvance);
// }
//
// /**
// * Scenario 11: Single transaction which is a repayment many days early
// but still does not qualify for 'in advance'.
// */
// @Test
// public void
// givenRepaymentOfInstallmentBeforeDueDateButNotInAdvanceShouldPayoffInterestAndPrincipalComponents()
// {
// // setup
// installments =
// LoanScheduleTestDataHelper.createSimpleLoanScheduleWithFirstInstallmentFullyPaid(july2nd,
// usDollars);
// LoanRepaymentScheduleInstallment firstInstallment =
// this.installments.get(0);
// LocalDate paymentBeforeDueDateButNotInAdvanceDate =
// firstInstallment.getDueDate().plusDays(1);
//
// Money amount = new MoneyBuilder().with(usDollars).with("900.00").build();
// LoanTransaction paymentBeforeDueDateButNotInAdvance = new
// LoanTransactionBuilder().repayment().with(paymentBeforeDueDateButNotInAdvanceDate).with(amount).build();
//
// // execute test
// processor.handleTransaction(paymentBeforeDueDateButNotInAdvance,
// usDollars, installments);
//
// // verification of derived fields on installments
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf("700.00",
// "200.00", secondInstallment);
//
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf("700.00",
// "200.00", paymentBeforeDueDateButNotInAdvance);
// }
//
//
// /**
// * Scenario 12: Single transaction which is a repayment many days early
// but still does not qualify for 'in advance'.
// */
// @Test
// public void
// givenLateRepaymentOfInstallmentShouldPayoffInterestAndPrincipalComponentsOfOverdueInstallmentsWithNoWaiveOfInterest()
// {
// // setup
// installments =
// LoanScheduleTestDataHelper.createSimpleLoanSchedule(july2nd, usDollars);
// LoanRepaymentScheduleInstallment firstInstallment =
// this.installments.get(0);
// LocalDate latePaymentDate = firstInstallment.getDueDate().plusMonths(5);
//
// Money amount = new
// MoneyBuilder().with(usDollars).with("3600.00").build();
// LoanTransaction lateRepaymentTransaction = new
// LoanTransactionBuilder().repayment().with(latePaymentDate).with(amount).build();
//
// // execute test
// processor.handleTransaction(lateRepaymentTransaction, usDollars,
// installments);
//
// // verification of derived fields on installments
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("1000.00"),
// interestOf("200.00"), interestWaivedOf("0.00"), firstInstallment,
// usDollars);
//
// LoanRepaymentScheduleInstallment secondInstallment =
// this.installments.get(1);
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("1000.00"),
// interestOf("200.00"), interestWaivedOf("0.00"), secondInstallment,
// usDollars);
//
// LoanRepaymentScheduleInstallment thirdInstallment =
// this.installments.get(2);
// assertThatLoanInstallmentHasDerivedFieldsOf(principalOf("1000.00"),
// interestOf("200.00"), interestWaivedOf("0.00"), thirdInstallment,
// usDollars);
//
// assertThatLoanTransactionHasDerivedFieldsOf(principalOf("3000.00"),
// interestOf("600.00"), lateRepaymentTransaction, usDollars);
// }
//
//
// private void
// assertThatLoanTransactionHasDerivedFieldsForPrincipalInterestOf(
// final String principal, final String interest, final LoanTransaction
// transaction) {
//
// Money expectedInterestPortion = new
// MoneyBuilder().with(usDollars).with(interest).build();
// assertThat(transaction.getInterestPortion(usDollars).toString(),
// is(expectedInterestPortion.toString()));
//
// Money expectedPrincipalPortion = new
// MoneyBuilder().with(usDollars).with(principal).build();
// assertThat(transaction.getPrincipalPortion(usDollars).toString(),
// is(expectedPrincipalPortion.toString()));
// }
//
// private void
// assertThatLoanInstallmentHasDerivedFieldsForPrincipalInterestOf(final
// String principal, final String interest,
// final LoanRepaymentScheduleInstallment installment) {
// Money expectedInterestCompleted = new
// MoneyBuilder().with(usDollars).with(interest).build();
// assertThat(installment.getInterestCompleted(usDollars).toString(),
// is(expectedInterestCompleted.toString()));
//
// Money expectedPrincipalCompleted = new
// MoneyBuilder().with(usDollars).with(principal).build();
// assertThat(installment.getPrincipalCompleted(usDollars).toString(),
// is(expectedPrincipalCompleted.toString()));
// }
//
// private void assertThatLoanTransactionHasDerivedFieldsOf(
// final String principal,
// final String interest,
// final LoanTransaction transaction, final MonetaryCurrency currency) {
//
// Money expectedPrincipalPortion = new
// MoneyBuilder().with(currency).with(principal).build();
// assertThat("Principal portion of transaction not as expected: ",
// transaction.getPrincipalPortion(currency).toString(),
// is(expectedPrincipalPortion.toString()));
//
// Money expectedInterestPortion = new
// MoneyBuilder().with(currency).with(interest).build();
// assertThat("Interest portion of transaction not as expected: ",
// transaction.getInterestPortion(currency).toString(),
// is(expectedInterestPortion.toString()));
// }
//
// private void assertThatLoanInstallmentHasDerivedFieldsOf(
// final String principal,
// final String interest,
// final String interestWaived,
// final LoanRepaymentScheduleInstallment installment, final
// MonetaryCurrency currency) {
//
// Money expectedPrincipalCompleted = new
// MoneyBuilder().with(currency).with(principal).build();
// assertThat("principal not as expected",
// installment.getPrincipalCompleted(currency).toString(),
// is(expectedPrincipalCompleted.toString()));
//
// Money expectedInterestCompleted = new
// MoneyBuilder().with(currency).with(interest).build();
// assertThat("interest completed not as expected: ",installment.getInterestCompleted(currency).toString(),
// is(expectedInterestCompleted.toString()));
//
// Money expectedInterestWaived = new
// MoneyBuilder().with(currency).with(interestWaived).build();
// assertThat("interest waived not as expected: ",
// installment.getInterestWaived(currency).toString(),
// is(expectedInterestWaived.toString()));
// }
//
// private String principalOf(final String value) {
// return value;
// }
//
// private String interestOf(final String value) {
// return value;
// }
//
// private String interestWaivedOf(final String value) {
// return value;
// }
}