Transporting interest to the calculation. Required some minor restructuring because interest is in the case, rather than the case parameters.
diff --git a/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java b/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
index 2268871..b7170d0 100644
--- a/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
+++ b/api/src/main/java/io/mifos/portfolio/api/v1/domain/ChargeDefinition.java
@@ -39,7 +39,8 @@
@SuppressWarnings("WeakerAccess")
public enum ChargeMethod {
FIXED,
- PROPORTIONAL
+ PROPORTIONAL,
+ INTEREST
}
@ValidIdentifier
diff --git a/component-test/src/main/java/io/mifos/portfolio/Fixture.java b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
index 8ebb702..f533a12 100644
--- a/component-test/src/main/java/io/mifos/portfolio/Fixture.java
+++ b/component-test/src/main/java/io/mifos/portfolio/Fixture.java
@@ -118,7 +118,7 @@
final Set<AccountAssignment> accountAssignments = new HashSet<>();
ret.setAccountAssignments(accountAssignments);
ret.setCurrentState(Case.State.CREATED.name());
- ret.setInterest(BigDecimal.valueOf(10_0000, 4));
+ ret.setInterest(BigDecimal.valueOf(10_00, 2));
final CaseParameters caseParameters = getTestCaseParameters();
final Gson gson = new Gson();
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
index cc2c74c..4ab454a 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestAccountingInteractionInLoanWorkflow.java
@@ -27,8 +27,10 @@
import io.mifos.individuallending.api.v1.domain.workflow.Action;
import io.mifos.individuallending.api.v1.events.IndividualLoanCommandEvent;
import io.mifos.individuallending.api.v1.events.IndividualLoanEventConstants;
-import io.mifos.portfolio.api.v1.domain.*;
-import io.mifos.portfolio.api.v1.events.ChargeDefinitionEvent;
+import io.mifos.portfolio.api.v1.domain.Case;
+import io.mifos.portfolio.api.v1.domain.CostComponent;
+import io.mifos.portfolio.api.v1.domain.Product;
+import io.mifos.portfolio.api.v1.domain.TaskDefinition;
import io.mifos.portfolio.api.v1.events.EventConstants;
import io.mifos.rhythm.spi.v1.client.BeatListener;
import io.mifos.rhythm.spi.v1.domain.BeatPublish;
@@ -126,13 +128,6 @@
setFeeToFixedValue(product.getIdentifier(), ChargeIdentifiers.LOAN_ORIGINATION_FEE_ID, LOAN_ORIGINATION_FEE_AMOUNT);
setFeeToFixedValue(product.getIdentifier(), ChargeIdentifiers.DISBURSEMENT_FEE_ID, DISBURSEMENT_FEE_AMOUNT);
- final ChargeDefinition interestChargeDefinition = portfolioManager.getChargeDefinition(product.getIdentifier(), ChargeIdentifiers.INTEREST_ID);
- interestChargeDefinition.setAmount(Fixture.INTEREST_RATE);
-
- portfolioManager.changeChargeDefinition(product.getIdentifier(), interestChargeDefinition.getIdentifier(), interestChargeDefinition);
- Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_CHARGE_DEFINITION,
- new ChargeDefinitionEvent(product.getIdentifier(), interestChargeDefinition.getIdentifier())));
-
taskDefinition = createTaskDefinition(product);
portfolioManager.enableProduct(product.getIdentifier(), true);
diff --git a/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java b/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
index 6673c26..685c183 100644
--- a/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
+++ b/component-test/src/main/java/io/mifos/portfolio/TestChargeDefinitions.java
@@ -62,11 +62,11 @@
ChargeIdentifiers.DISBURSE_PAYMENT_ID,
ChargeIdentifiers.TRACK_DISBURSAL_PAYMENT_ID,
ChargeIdentifiers.TRACK_RETURN_PRINCIPAL_ID,
+ ChargeIdentifiers.INTEREST_ID,
ChargeIdentifiers.REPAYMENT_ID)
.collect(Collectors.toSet());
final Set<String> expectedChangeableChargeDefinitionIdentifiers = Stream.of(
ChargeIdentifiers.DISBURSEMENT_FEE_ID,
- ChargeIdentifiers.INTEREST_ID,
ChargeIdentifiers.LATE_FEE_ID,
ChargeIdentifiers.LOAN_ORIGINATION_FEE_ID,
ChargeIdentifiers.PROCESSING_FEE_ID)
@@ -154,24 +154,24 @@
@Test
- public void shouldChangeInterestChargeDefinition() throws InterruptedException {
+ public void shouldChangeDisbursementFeeChargeDefinition() throws InterruptedException {
final Product product = createProduct();
- final ChargeDefinition interestChargeDefinition
- = portfolioManager.getChargeDefinition(product.getIdentifier(), ChargeIdentifiers.INTEREST_ID);
- interestChargeDefinition.setAmount(Fixture.INTEREST_RATE);
+ final ChargeDefinition disbursementFeeDefinition
+ = portfolioManager.getChargeDefinition(product.getIdentifier(), ChargeIdentifiers.DISBURSEMENT_FEE_ID);
+ disbursementFeeDefinition.setAmount(BigDecimal.valueOf(10_0000, 4));
portfolioManager.changeChargeDefinition(
product.getIdentifier(),
- interestChargeDefinition.getIdentifier(),
- interestChargeDefinition);
+ disbursementFeeDefinition.getIdentifier(),
+ disbursementFeeDefinition);
Assert.assertTrue(this.eventRecorder.wait(EventConstants.PUT_CHARGE_DEFINITION,
- new ChargeDefinitionEvent(product.getIdentifier(), interestChargeDefinition.getIdentifier())));
+ new ChargeDefinitionEvent(product.getIdentifier(), disbursementFeeDefinition.getIdentifier())));
final ChargeDefinition chargeDefinitionAsChanged
- = portfolioManager.getChargeDefinition(product.getIdentifier(), interestChargeDefinition.getIdentifier());
+ = portfolioManager.getChargeDefinition(product.getIdentifier(), disbursementFeeDefinition.getIdentifier());
- Assert.assertEquals(interestChargeDefinition, chargeDefinitionAsChanged);
+ Assert.assertEquals(disbursementFeeDefinition, chargeDefinitionAsChanged);
}
@Test
diff --git a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
index 7d5be70..9488c60 100644
--- a/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
+++ b/service/src/main/java/io/mifos/individuallending/IndividualLendingPatternFactory.java
@@ -190,14 +190,15 @@
final ChargeDefinition interestCharge = charge(
INTEREST_NAME,
Action.ACCEPT_PAYMENT,
- BigDecimal.valueOf(0.05),
+ BigDecimal.ONE,
CUSTOMER_LOAN,
INTEREST_INCOME);
interestCharge.setForCycleSizeUnit(ChronoUnit.YEARS);
interestCharge.setAccrueAction(Action.APPLY_INTEREST.name());
interestCharge.setAccrualAccountDesignator(INTEREST_ACCRUAL);
interestCharge.setProportionalTo(ChargeProportionalDesignator.RUNNING_BALANCE_DESIGNATOR.getValue());
- interestCharge.setReadOnly(false);
+ interestCharge.setChargeMethod(ChargeDefinition.ChargeMethod.INTEREST);
+ interestCharge.setReadOnly(true);
final ChargeDefinition customerRepaymentCharge = new ChargeDefinition();
customerRepaymentCharge.setChargeAction(Action.ACCEPT_PAYMENT.name());
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java b/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java
index 29a6592..67725d2 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/CostComponentService.java
@@ -102,7 +102,7 @@
caseParameters.getMaximumBalance(),
BigDecimal.ZERO,
BigDecimal.ZERO,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -121,7 +121,7 @@
caseParameters.getMaximumBalance(),
BigDecimal.ZERO,
BigDecimal.ZERO,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -141,7 +141,7 @@
caseParameters.getMaximumBalance(),
BigDecimal.ZERO,
BigDecimal.ZERO,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -198,7 +198,7 @@
caseParameters.getMaximumBalance(),
currentBalance,
disbursalSize,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -238,7 +238,7 @@
caseParameters.getMaximumBalance(),
currentBalance,
BigDecimal.ZERO,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -274,7 +274,11 @@
final List<ScheduledCharge> hypotheticalScheduledCharges = individualLoanService.getScheduledCharges(
productIdentifier,
hypotheticalScheduledActions);
- loanPaymentSize = getLoanPaymentSize(currentBalance, minorCurrencyUnitDigits, hypotheticalScheduledCharges);
+ loanPaymentSize = getLoanPaymentSize(
+ currentBalance,
+ dataContextOfAction.getInterestAsFraction(),
+ minorCurrencyUnitDigits,
+ hypotheticalScheduledCharges);
}
final List<ScheduledCharge> scheduledChargesForThisAction = individualLoanService.getScheduledCharges(
@@ -298,7 +302,7 @@
caseParameters.getMaximumBalance(),
currentBalance,
loanPaymentSize,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -382,7 +386,7 @@
caseParameters.getMaximumBalance(),
currentBalance,
BigDecimal.ZERO,
- dataContextOfAction.getCustomerCase().getInterest(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
true);
}
@@ -440,7 +444,7 @@
final CostComponent costComponent = costComponentMap
.computeIfAbsent(scheduledCharge.getChargeDefinition(), CostComponentService::constructEmptyCostComponent);
- final BigDecimal chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge)
+ final BigDecimal chargeAmount = howToApplyScheduledChargeToAmount(scheduledCharge, interest)
.apply(amountProportionalTo)
.setScale(minorCurrencyUnitDigits, BigDecimal.ROUND_HALF_EVEN);
adjustBalances(
@@ -496,34 +500,42 @@
}
private static Optional<ChargeProportionalDesignator> proportionalToDesignator(final ScheduledCharge scheduledCharge) {
- if (!scheduledCharge.getChargeDefinition().getChargeMethod().equals(ChargeDefinition.ChargeMethod.PROPORTIONAL))
+ if (!scheduledCharge.getChargeDefinition().getChargeMethod().equals(ChargeDefinition.ChargeMethod.PROPORTIONAL) &&
+ !scheduledCharge.getChargeDefinition().getChargeMethod().equals(ChargeDefinition.ChargeMethod.INTEREST))
return Optional.of(ChargeProportionalDesignator.NOT_PROPORTIONAL);
return ChargeProportionalDesignator.fromString(scheduledCharge.getChargeDefinition().getProportionalTo());
}
private static Function<BigDecimal, BigDecimal> howToApplyScheduledChargeToAmount(
- final ScheduledCharge scheduledCharge)
+ final ScheduledCharge scheduledCharge, final BigDecimal interest)
{
switch (scheduledCharge.getChargeDefinition().getChargeMethod())
{
- case FIXED:
+ case FIXED: {
return (amountProportionalTo) -> scheduledCharge.getChargeDefinition().getAmount();
- case PROPORTIONAL:
- return (amountProportionalTo) ->
- PeriodChargeCalculator.chargeAmountPerPeriod(scheduledCharge, RUNNING_CALCULATION_PRECISION)
- .multiply(amountProportionalTo);
- default:
+ }
+ case PROPORTIONAL: {
+ final BigDecimal chargeAmountPerPeriod = PeriodChargeCalculator.chargeAmountPerPeriod(scheduledCharge, scheduledCharge.getChargeDefinition().getAmount(), RUNNING_CALCULATION_PRECISION);
+ return chargeAmountPerPeriod::multiply;
+ }
+ case INTEREST: {
+ final BigDecimal chargeAmountPerPeriod = PeriodChargeCalculator.chargeAmountPerPeriod(scheduledCharge, interest, RUNNING_CALCULATION_PRECISION);
+ return chargeAmountPerPeriod::multiply;
+ }
+ default: {
return (amountProportionalTo) -> BigDecimal.ZERO;
+ }
}
}
static BigDecimal getLoanPaymentSize(final BigDecimal startingBalance,
+ final BigDecimal interest,
final int minorCurrencyUnitDigits,
final List<ScheduledCharge> scheduledCharges) {
final int precision = startingBalance.precision() + minorCurrencyUnitDigits + EXTRA_PRECISION;
final Map<Period, BigDecimal> accrualRatesByPeriod
- = PeriodChargeCalculator.getPeriodAccrualInterestRate(scheduledCharges, precision);
+ = PeriodChargeCalculator.getPeriodAccrualInterestRate(interest, scheduledCharges, precision);
final int periodCount = accrualRatesByPeriod.size();
if (periodCount == 0)
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
index f7c2485..af636fc 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/DataContextOfAction.java
@@ -23,6 +23,7 @@
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
@@ -34,6 +35,7 @@
private final CaseEntity customerCase;
private final CaseParameters caseParameters;
private final List<AccountAssignment> oneTimeAccountAssignments;
+ private final BigDecimal interestAsFraction;
DataContextOfAction(final @Nonnull ProductEntity product,
final @Nonnull CaseEntity customerCase,
@@ -43,6 +45,7 @@
this.customerCase = customerCase;
this.caseParameters = caseParameters;
this.oneTimeAccountAssignments = oneTimeAccountAssignments == null ? Collections.emptyList() : oneTimeAccountAssignments;
+ interestAsFraction = customerCase.getInterest().divide(BigDecimal.valueOf(100), 4, BigDecimal.ROUND_HALF_EVEN);;
}
public @Nonnull ProductEntity getProduct() {
@@ -68,4 +71,8 @@
public String getMessageForCharge(final Action action) {
return getCompoundIdentifer() + "." + action.name();
}
+
+ BigDecimal getInterestAsFraction() {
+ return interestAsFraction;
+ }
}
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java b/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
index b24d4d7..0f77033 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/IndividualLoanService.java
@@ -57,6 +57,7 @@
final BigDecimal loanPaymentSize = CostComponentService.getLoanPaymentSize(
dataContextOfAction.getCaseParameters().getMaximumBalance(),
+ dataContextOfAction.getInterestAsFraction(),
minorCurrencyUnitDigits,
scheduledCharges);
@@ -65,7 +66,7 @@
minorCurrencyUnitDigits,
scheduledCharges,
loanPaymentSize,
- dataContextOfAction.getCustomerCase().getInterest());
+ dataContextOfAction.getInterestAsFraction());
final Set<ChargeName> chargeNames = scheduledCharges.stream()
.map(IndividualLoanService::chargeNameFromChargeDefinition)
@@ -179,7 +180,7 @@
return scheduledAction.repaymentPeriod;
}
- private List<ScheduledCharge> getScheduledCharges(final List<ScheduledAction> scheduledActions,
+ static List<ScheduledCharge> getScheduledCharges(final List<ScheduledAction> scheduledActions,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction) {
return scheduledActions.stream()
@@ -192,7 +193,7 @@
.collect(Collectors.toList());
}
- private Stream<ChargeDefinition> getChargeDefinitionStream(
+ private static Stream<ChargeDefinition> getChargeDefinitionStream(
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByChargeAction,
final Map<String, List<ChargeDefinition>> chargeDefinitionsMappedByAccrueAction,
final ScheduledAction scheduledAction) {
diff --git a/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java b/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java
index 58cac97..39bb325 100644
--- a/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java
+++ b/service/src/main/java/io/mifos/individuallending/internal/service/PeriodChargeCalculator.java
@@ -38,12 +38,14 @@
{
}
- static Map<Period, BigDecimal> getPeriodAccrualInterestRate(final List<ScheduledCharge> scheduledCharges,
- final int precision) {
+ static Map<Period, BigDecimal> getPeriodAccrualInterestRate(
+ final BigDecimal interest,
+ final List<ScheduledCharge> scheduledCharges,
+ final int precision) {
return scheduledCharges.stream()
.filter(PeriodChargeCalculator::accruedInterestCharge)
.collect(Collectors.groupingBy(scheduledCharge -> scheduledCharge.getScheduledAction().repaymentPeriod,
- Collectors.mapping(x -> chargeAmountPerPeriod(x, precision), RateCollectors.compound(precision))));
+ Collectors.mapping(x -> chargeAmountPerPeriod(x, interest, precision), RateCollectors.compound(precision))));
}
private static boolean accruedInterestCharge(final ScheduledCharge scheduledCharge)
@@ -52,15 +54,16 @@
scheduledCharge.getChargeDefinition().getAccrueAction() != null &&
scheduledCharge.getChargeDefinition().getAccrueAction().equals(Action.APPLY_INTEREST.name()) &&
scheduledCharge.getScheduledAction().action == Action.ACCEPT_PAYMENT &&
- scheduledCharge.getScheduledAction().actionPeriod != null;
+ scheduledCharge.getScheduledAction().actionPeriod != null &&
+ scheduledCharge.getChargeDefinition().getChargeMethod() == ChargeDefinition.ChargeMethod.INTEREST;
}
- static BigDecimal chargeAmountPerPeriod(final ScheduledCharge scheduledCharge, final int precision)
+ static BigDecimal chargeAmountPerPeriod(final ScheduledCharge scheduledCharge, final BigDecimal amount, final int precision)
{
final ChargeDefinition chargeDefinition = scheduledCharge.getChargeDefinition();
final ScheduledAction scheduledAction = scheduledCharge.getScheduledAction();
if (chargeDefinition.getForCycleSizeUnit() == null)
- return chargeDefinition.getAmount();
+ return amount;
final BigDecimal actionPeriodDuration
= BigDecimal.valueOf(
@@ -84,7 +87,7 @@
final int accrualPeriodsInActionPeriod = actionPeriodDuration.divide(
accrualPeriodDuration.orElse(actionPeriodDuration), precision, BigDecimal.ROUND_HALF_EVEN)
.intValueExact();
- final BigDecimal rateForAccrualPeriod = chargeDefinition.getAmount().divide(
+ final BigDecimal rateForAccrualPeriod = amount.divide(
accrualPeriodsInCycle, precision, BigDecimal.ROUND_HALF_EVEN);
return createCompoundedRate(rateForAccrualPeriod, accrualPeriodsInActionPeriod, precision);
}
diff --git a/service/src/main/resources/db/migrations/mariadb/V6__interest_and_charges.sql b/service/src/main/resources/db/migrations/mariadb/V6__interest_and_charges.sql
index a10b21c..78e109a 100644
--- a/service/src/main/resources/db/migrations/mariadb/V6__interest_and_charges.sql
+++ b/service/src/main/resources/db/migrations/mariadb/V6__interest_and_charges.sql
@@ -14,4 +14,4 @@
-- limitations under the License.
--
-ALTER TABLE bastet_cases ADD COLUMN interest DECIMAL(7,4) NULL DEFAULT NULL;
\ No newline at end of file
+ALTER TABLE bastet_cases ADD COLUMN interest DECIMAL(5,2) NULL DEFAULT NULL;
\ No newline at end of file
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java b/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
index c649180..7f73106 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/Fixture.java
@@ -86,7 +86,6 @@
}
static ScheduledCharge scheduledInterestBookingCharge(
- final double amount,
final LocalDate initialDate,
final int chargeDateDelta,
final int periodBeginDelta,
@@ -99,12 +98,12 @@
new Period(chargeDate, periodLength),
getPeriod(initialDate, periodBeginDelta, periodLength));
final ChargeDefinition chargeDefinition = new ChargeDefinition();
- chargeDefinition.setChargeMethod(ChargeDefinition.ChargeMethod.PROPORTIONAL);
+ chargeDefinition.setChargeMethod(ChargeDefinition.ChargeMethod.INTEREST);
chargeDefinition.setForCycleSizeUnit(ChronoUnit.YEARS);
chargeDefinition.setIdentifier("blah");
chargeDefinition.setAccrueAction(Action.APPLY_INTEREST.name());
chargeDefinition.setChargeAction(Action.ACCEPT_PAYMENT.name());
- chargeDefinition.setAmount(BigDecimal.valueOf(amount));
+ chargeDefinition.setAmount(BigDecimal.ONE);
chargeDefinition.setFromAccountDesignator(AccountDesignators.CUSTOMER_LOAN);
chargeDefinition.setAccrualAccountDesignator(AccountDesignators.INTEREST_ACCRUAL);
chargeDefinition.setToAccountDesignator(AccountDesignators.INTEREST_INCOME);
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
index d8691bb..1bb13b1 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/IndividualLoanServiceTest.java
@@ -186,7 +186,7 @@
final ChargeDefinition processingFeeCharge = getFixedSingleChargeDefinition(10.0, Action.OPEN, PROCESSING_FEE_ID, AccountDesignators.PROCESSING_FEE_INCOME);
final ChargeDefinition loanOriginationFeeCharge = getFixedSingleChargeDefinition(100.0, Action.APPROVE, LOAN_ORIGINATION_FEE_ID, AccountDesignators.ORIGINATION_FEE_INCOME);
final List<ChargeDefinition> defaultChargesWithFeesReplaced =
- chargesWithInterestRate(0.01).stream().map(x -> {
+ charges().stream().map(x -> {
switch (x.getIdentifier()) {
case PROCESSING_FEE_ID:
return processingFeeCharge;
@@ -202,7 +202,7 @@
.caseParameters(caseParameters)
.initialDisbursementDate(initialDisbursementDate)
.chargeDefinitions(defaultChargesWithFeesReplaced)
- .interest(BigDecimal.valueOf(0.01))
+ .interest(BigDecimal.valueOf(1))
.expectChargeInstancesForActionDatePair(Action.OPEN, initialDisbursementDate, Collections.singletonList(processingFeeCharge))
.expectChargeInstancesForActionDatePair(Action.APPROVE, initialDisbursementDate,
Collections.singletonList(loanOriginationFeeCharge));
@@ -217,14 +217,14 @@
caseParameters.setPaymentCycle(new PaymentCycle(ChronoUnit.MONTHS, 1, 0, null, null));
caseParameters.setMaximumBalance(BigDecimal.valueOf(200000));
- final List<ChargeDefinition> charges = chargesWithInterestRate(0.10);
+ final List<ChargeDefinition> charges = charges();
return new TestCase("yearLoanTestCase")
.minorCurrencyUnitDigits(3)
.caseParameters(caseParameters)
.initialDisbursementDate(initialDisbursementDate)
.chargeDefinitions(charges)
- .interest(BigDecimal.valueOf(0.10));
+ .interest(BigDecimal.valueOf(10));
}
private static TestCase chargeDefaultsCase()
@@ -235,25 +235,18 @@
caseParameters.setPaymentCycle(new PaymentCycle(ChronoUnit.WEEKS, 1, 1, 0, 0));
caseParameters.setMaximumBalance(BigDecimal.valueOf(2000));
- final List<ChargeDefinition> charges = chargesWithInterestRate(0.05);
+ final List<ChargeDefinition> charges = charges();
return new TestCase("chargeDefaultsCase")
.minorCurrencyUnitDigits(2)
.caseParameters(caseParameters)
.initialDisbursementDate(initialDisbursementDate)
.chargeDefinitions(charges)
- .interest(BigDecimal.valueOf(0.05));
+ .interest(BigDecimal.valueOf(5));
}
- private static List<ChargeDefinition> chargesWithInterestRate(final double interestRate) {
- final List<ChargeDefinition> defaultLoanCharges = IndividualLendingPatternFactory.defaultIndividualLoanCharges();
-
- defaultLoanCharges.forEach(x -> {
- if (x.getIdentifier().equals(ChargeIdentifiers.INTEREST_ID))
- x.setAmount(BigDecimal.valueOf(interestRate));
- });
-
- return defaultLoanCharges;
+ private static List<ChargeDefinition> charges() {
+ return IndividualLendingPatternFactory.defaultIndividualLoanCharges();
}
private static ChargeDefinition getFixedSingleChargeDefinition(
diff --git a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java b/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java
index 6b3c2ff..0961727 100644
--- a/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java
+++ b/service/src/test/java/io/mifos/individuallending/internal/service/PeriodChargeCalculatorTest.java
@@ -38,6 +38,7 @@
List<ScheduledCharge> scheduledCharges;
int precision;
Map<Period, BigDecimal> expectedPeriodRates;
+ private BigDecimal interest;
private TestCase(final String description) {
this.description = description;
@@ -64,6 +65,11 @@
"description='" + description + '\'' +
'}';
}
+
+ TestCase interest(BigDecimal newVal) {
+ this.interest = newVal;
+ return this;
+ }
}
@Parameterized.Parameters
@@ -79,8 +85,8 @@
{
final LocalDate initialDate = LocalDate.now();
final List<ScheduledCharge> scheduledCharges = new ArrayList<>();
- scheduledCharges.add(scheduledInterestBookingCharge(0.01, initialDate, 0, 0, 1));
- scheduledCharges.add(scheduledInterestBookingCharge(0.01, initialDate, 1, 1, 1));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 0, 0, 1));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 1, 1, 1));
final BigDecimal dailyInterestRate = BigDecimal.valueOf(0.01)
.divide(BigDecimal.valueOf(365.2425), 20, BigDecimal.ROUND_HALF_EVEN);
@@ -90,6 +96,7 @@
expectedPeriodRates.put(getPeriod(initialDate, 1, 1), dailyInterestRate);
return new TestCase("simpleCase")
+ .interest(BigDecimal.valueOf(0.01))
.scheduledCharges(scheduledCharges)
.precision(20)
.expectedPeriodRates(expectedPeriodRates);
@@ -99,8 +106,8 @@
{
final LocalDate initialDate = LocalDate.now();
final List<ScheduledCharge> scheduledCharges = new ArrayList<>();
- scheduledCharges.add(scheduledInterestBookingCharge(0.10, initialDate, 2, 0, 3));
- scheduledCharges.add(scheduledInterestBookingCharge(0.10, initialDate, 4, 2, 2));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 2, 0, 3));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 4, 2, 2));
final BigDecimal dailyInterestRate = BigDecimal.valueOf(0.10)
.divide(BigDecimal.valueOf(365.2425), 20, BigDecimal.ROUND_HALF_EVEN);
@@ -110,6 +117,7 @@
expectedPeriodRates.put(getPeriod(initialDate, 2, 2), PeriodChargeCalculator.createCompoundedRate(dailyInterestRate, 2, 20));
return new TestCase("bitOfCompoundingCase")
+ .interest(BigDecimal.valueOf(0.10))
.scheduledCharges(scheduledCharges)
.precision(20)
.expectedPeriodRates(expectedPeriodRates);
@@ -119,14 +127,15 @@
{
final LocalDate initialDate = LocalDate.now();
final List<ScheduledCharge> scheduledCharges = new ArrayList<>();
- scheduledCharges.add(scheduledInterestBookingCharge(0.00, initialDate, 2, 0, 3));
- scheduledCharges.add(scheduledInterestBookingCharge(0.00, initialDate, 4, 2, 2));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 2, 0, 3));
+ scheduledCharges.add(scheduledInterestBookingCharge(initialDate, 4, 2, 2));
final Map<Period, BigDecimal> expectedPeriodRates = new HashMap<>();
expectedPeriodRates.put(getPeriod(initialDate, 0, 3), BigDecimal.ZERO.setScale(20, BigDecimal.ROUND_UNNECESSARY));
expectedPeriodRates.put(getPeriod(initialDate, 2, 2), BigDecimal.ZERO.setScale(20, BigDecimal.ROUND_UNNECESSARY));
return new TestCase("zeroInterestPerPeriod")
+ .interest(BigDecimal.valueOf(0.00))
.scheduledCharges(scheduledCharges)
.precision(20)
.expectedPeriodRates(expectedPeriodRates);
@@ -141,7 +150,7 @@
@Test
public void getPeriodAccrualRatesTest()
{
- final Map<Period, BigDecimal> periodRates = PeriodChargeCalculator.getPeriodAccrualInterestRate(testCase.scheduledCharges, testCase.precision);
+ final Map<Period, BigDecimal> periodRates = PeriodChargeCalculator.getPeriodAccrualInterestRate(testCase.interest, testCase.scheduledCharges, testCase.precision);
Assert.assertEquals(testCase.expectedPeriodRates, periodRates);
}
}