/*
* Copyright (c) 2005-2011 Grameen Foundation USA
* All rights reserved.
*
* Licensed 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.
*
* See also http://www.apache.org/licenses/LICENSE-2.0.html for an
* explanation of the license and how it is applied.
*/
package org.mifos.accounts.loan.schedule.calculation;
import static java.util.Arrays.asList;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
import static org.mifos.framework.TestUtils.getDate;
import java.math.BigDecimal;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.mifos.accounts.loan.business.RepaymentResultsHolder;
import org.mifos.accounts.loan.schedule.domain.Installment;
import org.mifos.accounts.loan.schedule.domain.Schedule;
public class ScheduleCalculatorTest {
private ScheduleCalculator scheduleCalculator;
private Schedule schedule;
@Before
public void setup() {
scheduleCalculator = new ScheduleCalculator();
}
@Test
public void withOneInstallmentAdjusted() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(280d), getDate(25, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 230.31, 17.36);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.62, 14.62, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withExactPaymentOnTime() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(262.64d), getDate(25, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void exactPaymentOnTimeWithFeesAndPenalty() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0, 1, 2, 3, 4);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(272.64d), getDate(25, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withShortPaymentOnTime() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(240d), getDate(25, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 22.64, 219.6);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withTwoInstallmentsAdjusted() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(550d), getDate(25, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 0, 247.67);
assertInstallmentPrincipals(installment3, 252.22, 212.53, 39.69);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 9.29, 9.29, 0);
assertInstallmentInterests(installment3, 9.6, 9.6, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withOverDueInterests() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(550d), getDate(30, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 0, 247.67);
assertInstallmentPrincipals(installment3, 252.22, 215.82, 36.4);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 7.79, 7.79, 2.49);
assertInstallmentInterests(installment3, 9.66, 9.66, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withOverDueInterestsAndFeesAndPenalty() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0, 1, 2, 3, 4);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0, 1, 2, 3, 4);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(560d), getDate(30, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 0, 247.67);
assertInstallmentPrincipals(installment3, 252.22, 215.82, 36.4);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 7.79, 7.79, 2.49);
assertInstallmentInterests(installment3, 9.66, 9.66, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withShortPaymentBeforeDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(240d), getDate(23, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 21.32, 220.92);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 1.03, 1.03, 19.08);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void shortPaymentBeforeDueDateWithFeesAndPenalty() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0, 1, 2, 3, 4);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(240d), getDate(23, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 21.32, 220.92);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 1.03, 1.03, 19.08);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withShortPaymentAfterDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(240d), getDate(29, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 22.64, 219.6);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
assertInstallmentForExtraInterests(installment1, 0, 0, 0);
assertInstallmentForExtraInterests(installment2, 0.64, 0.64, 0);
assertInstallmentForExtraInterests(installment3, 0, 0, 0);
assertInstallmentForExtraInterests(installment4, 0, 0, 0);
}
@Test
public void withExcessPaymentAfterDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(280d), getDate(29, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 232.94, 14.73);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 12.71, 12.71, 1.99);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
assertInstallmentForExtraInterests(installment1, 0, 0, 0);
assertInstallmentForExtraInterests(installment2, 0.64, 0, 0.64);
assertInstallmentForExtraInterests(installment3, 0, 0, 0);
assertInstallmentForExtraInterests(installment4, 0, 0, 0);
}
@Test
public void withExactPaymentAfterDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(262.64d), getDate(29, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 0, 20.40);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
assertInstallmentForExtraInterests(installment1, 0, 0, 0);
assertInstallmentForExtraInterests(installment2, 0.64, 0.64, 0);
assertInstallmentForExtraInterests(installment3, 0, 0, 0);
assertInstallmentForExtraInterests(installment4, 0, 0, 0);
}
@Test
public void withNoPaymentPaymentAfterDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.computeExtraInterest(schedule, getDate(26, 12, 2010));
assertInstallmentPrincipals(installment1, 242.24, 242.24, 0);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 20.40, 20.40, 0);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
assertInstallmentForExtraInterests(installment1, 0, 0, 0);
assertInstallmentForExtraInterests(installment2, 14.66, 14.66, 0);
assertInstallmentForExtraInterests(installment3, 10.1, 10.1, 0);
assertInstallmentForExtraInterests(installment4, 5.31, 5.31, 0);
}
@Test
public void withExcessPaymentBeforeDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(280d), getDate(23, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 228.99, 18.68);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 0.97, 0.97, 19.08);
assertInstallmentInterests(installment2, 14.59, 14.59, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withExactPaymentBeforeDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(261.32d), getDate(23, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 247.67, 0);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 1, 1, 19.08);
assertInstallmentInterests(installment2, 14.96, 14.96, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void withInitialInstallmentAmountBeforeDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(262.64d), getDate(23, 9, 2010), false);
assertInstallmentPrincipals(installment1, 242.24, 0, 242.24);
assertInstallmentPrincipals(installment2, 247.67, 246.35, 1.32);
assertInstallmentPrincipals(installment3, 252.22, 252.22, 0);
assertInstallmentPrincipals(installment4, 257.87, 257.87, 0);
assertInstallmentInterests(installment1, 1, 1, 19.08);
assertInstallmentInterests(installment2, 14.93, 14.93, 0);
assertInstallmentInterests(installment3, 10.40, 10.40, 0);
assertInstallmentInterests(installment4, 5.09, 5.09, 0);
}
@Test
public void multiplePaymentsOnDisbursementDate() {
Installment installment1 = getInstallment(1, getDate(18, 10, 2010), 332.2, 3.8, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 333.4, 2.6, 0);
Installment installment3 = getInstallment(3, getDate(1, 11, 2010), 334.4, 1.3, 0);
schedule = new Schedule(getDate(11, 10, 2010), 0.000548, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(337d), getDate(11, 10, 2010), false);
assertInstallmentPrincipals(installment1, 332.2, 0, 332.2);
assertInstallmentPrincipals(installment2, 333.4, 328.6, 4.8);
assertInstallmentPrincipals(installment3, 334.4, 334.4, 0);
assertInstallmentInterests(installment1, 2.54, 2.54, 0);
assertInstallmentInterests(installment2, 2.54, 2.54, 0);
assertInstallmentInterests(installment3, 1.3, 1.3, 0);
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(10d), getDate(11, 10, 2010), false);
assertInstallmentPrincipals(installment1, 332.2, 0, 332.2);
assertInstallmentPrincipals(installment2, 333.4, 318.6, 14.8);
assertInstallmentPrincipals(installment3, 334.4, 334.4, 0);
assertInstallmentInterests(installment1, 2.54, 2.54, 0);
assertInstallmentInterests(installment2, 2.5, 2.5, 0);
assertInstallmentInterests(installment3, 1.3, 1.3, 0);
}
@Test
public void shouldComputeExtraInterestBeforeDisbursement() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(20, 8, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.0));
}
@Test
public void shouldComputeExtraInterestOnDisbursement() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(25, 8, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.0));
}
@Test
public void shouldComputeExtraInterestOnDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(25, 9, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.0));
}
@Test
public void shouldComputeOneDayExtraInterest() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(26, 9, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.16));
}
@Test
public void shouldComputeTwoDayExtraInterest() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(27, 9, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.32));
}
@Test
public void shouldComputeExtraInterestAfterPartPay() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(27, 9, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.32));
installment1.pay(BigDecimal.valueOf(100), getDate(27, 9, 2010));
scheduleCalculator.computeExtraInterest(schedule, getDate(28, 9, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.43));
}
@Test
public void shouldComputeExtraInterestAfterMultiplePaymentsOnSameDay() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.applyPayment(schedule, new BigDecimal(100), getDate(27, 9, 2010), false);
assertThat(installment2.getExtraInterestPaid().doubleValue(), is(0.0));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment1.getInterest().doubleValue(), is(20.40));
assertThat(installment1.getApplicableInterest().doubleValue(), is(20.40));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.32));
scheduleCalculator.applyPayment(schedule, new BigDecimal(200), getDate(27, 9, 2010), false);
assertThat(installment2.getExtraInterestPaid().doubleValue(), is(0.32));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.32));
assertThat(installment2.getInterestPaid().doubleValue(), is(1.00));
assertThat(installment2.getPrincipalDue().doubleValue(), is(211.63));
assertThat(installment2.getInterest().doubleValue(), is(14.96));
assertThat(installment2.getApplicableInterest().doubleValue(), is(13.30));
}
@Test
public void shouldComputeExtraFullPayment() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.applyPayment(schedule, new BigDecimal(262.64), getDate(25, 9, 2010), false);
scheduleCalculator.applyPayment(schedule, new BigDecimal(262.63), getDate(25, 10, 2010), false);
scheduleCalculator.computeExtraInterest(schedule, getDate(30, 12, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(0.0));
}
@Test
public void overdueOnLastInstallmentIsRecoveredInLastInstallment() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2));
scheduleCalculator.computeExtraInterest(schedule, getDate(20, 11, 2010));
assertThat(installment1.getExtraInterest().doubleValue(), is(0.0));
assertThat(installment2.getExtraInterest().doubleValue(), is(13.17));
}
@Test
public void shouldComputeRepaymentAmountWhenNoPastPaymentsMade() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
RepaymentResultsHolder repaymentResultsHolder = scheduleCalculator.computeRepaymentAmount(schedule, getDate(30, 11, 2010));
assertThat(repaymentResultsHolder.getTotalRepaymentAmount().doubleValue(),is(1063.83));
assertThat(repaymentResultsHolder.getWaiverAmount().doubleValue(),is(0.85));
}
@Test
public void computeRepaymentAmountShouldConsiderFeesAndPenaltyOfCurrentInstallmentAndDues() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0, 1, 2, 3, 4);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0, 1, 2, 3, 4);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0, 1, 2, 3, 4);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0, 1, 2, 3, 4);
Installment installment5 = getInstallment(5, getDate(25, 1, 2011), 257.87, 5.09, 0, 1, 2, 3, 4);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4, installment5));
RepaymentResultsHolder repaymentResultsHolder = scheduleCalculator.computeRepaymentAmount(schedule, getDate(30, 11, 2010));
assertThat(repaymentResultsHolder.getTotalRepaymentAmount().doubleValue(), is(1361.7));
assertThat(repaymentResultsHolder.getWaiverAmount().doubleValue(), is(0.85));
}
@Test
public void shouldComputeRepaymentAmountWhenLateExcessPaymentMade() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(500d), getDate(30, 10, 2010), false);
RepaymentResultsHolder repaymentResultsHolder = scheduleCalculator.computeRepaymentAmount(schedule, getDate(30, 11, 2010));
assertThat(repaymentResultsHolder.getTotalRepaymentAmount().doubleValue(),is(554.46));
assertThat(repaymentResultsHolder.getWaiverAmount().doubleValue(),is(0.85));
}
@Test
public void shouldComputeRepaymentAmountWhenOnDateExcessPaymentMade() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(500d), getDate(30, 10, 2010), false);
RepaymentResultsHolder repaymentResultsHolder = scheduleCalculator.computeRepaymentAmount(schedule, getDate(25, 12, 2010));
assertThat(repaymentResultsHolder.getTotalRepaymentAmount().doubleValue(),is(563.36));
assertThat(repaymentResultsHolder.getWaiverAmount().doubleValue(),is(5.09));
}
@Test
public void shouldComputeRepaymentAmountForOnTimePaymentsAndRepaymentDoneOnInstallmentDueDate() {
Installment installment1 = getInstallment(1, getDate(25, 9, 2010), 242.24, 20.40, 0);
Installment installment2 = getInstallment(2, getDate(25, 10, 2010), 247.67, 14.96, 0);
Installment installment3 = getInstallment(3, getDate(25, 11, 2010), 252.22, 10.40, 0);
Installment installment4 = getInstallment(4, getDate(25, 12, 2010), 257.87, 5.09, 0);
schedule = new Schedule(getDate(25, 8, 2010), 0.000658, BigDecimal.valueOf(1000d),
asList(installment1, installment2, installment3, installment4));
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(262.64), getDate(25, 9, 2010), false);
scheduleCalculator.applyPayment(schedule, BigDecimal.valueOf(262.63), getDate(25, 10, 2010), false);
BigDecimal repaymentAmount = scheduleCalculator.computeRepaymentAmount(schedule, getDate(25, 11, 2010)).getTotalRepaymentAmount();
assertThat(repaymentAmount.doubleValue(),is(520.49));
}
private void assertInstallmentPrincipals(Installment installment, double principal, double principalDue, double principalPaid) {
assertThat(installment.getPrincipal().doubleValue(), is(principal));
assertThat(installment.getPrincipalDue().doubleValue(), is(principalDue));
assertThat(installment.getPrincipalPaid().doubleValue(), is(principalPaid));
}
private void assertInstallmentInterests(Installment installment, double interest, double interestDue, double interestPaid) {
assertThat(installment.getApplicableInterest().doubleValue(), is(interest));
assertThat(installment.getInterestDue().doubleValue(), is(interestDue));
assertThat(installment.getInterestPaid().doubleValue(), is(interestPaid));
}
private void assertInstallmentForExtraInterests(Installment installment, double ExtraInterest, double ExtraInterestDue, double ExtraInterestPaid) {
assertThat(installment.getExtraInterest().doubleValue(), is(ExtraInterest));
assertThat(installment.getExtraInterestDue().doubleValue(), is(ExtraInterestDue));
assertThat(installment.getExtraInterestPaid().doubleValue(), is(ExtraInterestPaid));
}
private Installment getInstallment(int id, Date dueDate, double principal, double interest, double extraInterest) {
Installment installment = new Installment(id, dueDate, BigDecimal.valueOf(principal), BigDecimal.valueOf(interest), BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO);
installment.setExtraInterest(BigDecimal.valueOf(extraInterest));
return installment;
}
private Installment getInstallment(int id, Date dueDate, double principal, double interest, double extraInterest, double fees, double miscFees, double penalty, double miscPenalty) {
return new Installment(id, dueDate, BigDecimal.valueOf(principal), BigDecimal.valueOf(interest), BigDecimal.valueOf(extraInterest), BigDecimal.valueOf(fees), BigDecimal.valueOf(miscFees), BigDecimal.valueOf(penalty), BigDecimal.valueOf(miscPenalty));
}
}