FINERACT-1925: New repayment schedule
This commit is contained in:
+1
@@ -326,6 +326,7 @@ public class FineractProperties {
|
|||||||
private FineractTransactionProcessorItemProperties principalInterestPenaltiesFees;
|
private FineractTransactionProcessorItemProperties principalInterestPenaltiesFees;
|
||||||
private FineractTransactionProcessorItemProperties rbiIndia;
|
private FineractTransactionProcessorItemProperties rbiIndia;
|
||||||
private FineractTransactionProcessorItemProperties duePenaltyFeeInterestPrincipalInAdvancePrincipalPenaltyFeeInterest;
|
private FineractTransactionProcessorItemProperties duePenaltyFeeInterestPrincipalInAdvancePrincipalPenaltyFeeInterest;
|
||||||
|
private FineractTransactionProcessorItemProperties duePenaltyInterestPrincipalFeeInAdvancePenaltyInterestPrincipalFee;
|
||||||
private boolean errorNotFoundFail;
|
private boolean errorNotFoundFail;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-1
@@ -39,7 +39,8 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa
|
|||||||
* Due/late principal In advance principal In advance penalty In advance fee In advance interest
|
* Due/late principal In advance principal In advance penalty In advance fee In advance interest
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
public class DueDateRespectiveLoanRepaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor
|
||||||
|
extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
||||||
|
|
||||||
private static final String STRATEGY_CODE = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
private static final String STRATEGY_CODE = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
||||||
|
|
||||||
+304
@@ -0,0 +1,304 @@
|
|||||||
|
/**
|
||||||
|
* 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.domain.transactionprocessor.impl;
|
||||||
|
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||||
|
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeEffectiveDueDateComparator;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `First due/late penalty, interest, principal, fee, after in advance penalty, interest, principal, fee` style
|
||||||
|
* {@link LoanRepaymentScheduleTransactionProcessor}.
|
||||||
|
*
|
||||||
|
* For ALL types of transactions, pays off components in order of: Due/late penalty, Due/late interest, Due/late
|
||||||
|
* principal, Due/late fee, In advance penalty, In advance interest In advance principal, In advance fee
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor
|
||||||
|
extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
||||||
|
|
||||||
|
private static final String STRATEGY_CODE = "due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
|
||||||
|
|
||||||
|
private static final String STRATEGY_NAME = "Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee";
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCode() {
|
||||||
|
return STRATEGY_CODE;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return STRATEGY_NAME;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isTransactionInAdvanceOfInstallment(final int currentInstallmentIndex,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final LocalDate transactionDate) {
|
||||||
|
|
||||||
|
final LoanRepaymentScheduleInstallment currentInstallment = installments.get(currentInstallmentIndex);
|
||||||
|
|
||||||
|
return transactionDate.isBefore(currentInstallment.getDueDate());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For early/'in advance' repayments
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Money handleTransactionThatIsPaymentInAdvanceOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction, final Money paymentInAdvance,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges) {
|
||||||
|
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||||
|
final MonetaryCurrency currency = paymentInAdvance.getCurrency();
|
||||||
|
Money transactionAmountRemaining = paymentInAdvance;
|
||||||
|
Money principalPortion = Money.zero(currency);
|
||||||
|
Money interestPortion = Money.zero(currency);
|
||||||
|
Money feeChargesPortion = Money.zero(currency);
|
||||||
|
Money penaltyChargesPortion = Money.zero(currency);
|
||||||
|
|
||||||
|
if (loanTransaction.isChargesWaiver()) {
|
||||||
|
penaltyChargesPortion = currentInstallment.waivePenaltyChargesComponent(transactionDate,
|
||||||
|
loanTransaction.getPenaltyChargesPortion(currency));
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
|
||||||
|
feeChargesPortion = currentInstallment.waiveFeeChargesComponent(transactionDate,
|
||||||
|
loanTransaction.getFeeChargesPortion(currency));
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
|
||||||
|
} else if (loanTransaction.isInterestWaiver()) {
|
||||||
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
} else if (loanTransaction.isChargePayment()) {
|
||||||
|
if (loanTransaction.isPenaltyPayment()) {
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
} else {
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
} else {
|
||||||
|
// In advance penalty, interest, principal, fee
|
||||||
|
|
||||||
|
Money subPenaltyPortion;
|
||||||
|
subPenaltyPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subPenaltyPortion);
|
||||||
|
penaltyChargesPortion = penaltyChargesPortion.add(subPenaltyPortion);
|
||||||
|
|
||||||
|
Money subInterestPortion;
|
||||||
|
subInterestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subInterestPortion);
|
||||||
|
interestPortion = interestPortion.add(subInterestPortion);
|
||||||
|
|
||||||
|
Money subPrincipalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subPrincipalPortion);
|
||||||
|
principalPortion = principalPortion.add(subPrincipalPortion);
|
||||||
|
|
||||||
|
Money subFeePortion;
|
||||||
|
subFeePortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subFeePortion);
|
||||||
|
feeChargesPortion = feeChargesPortion.add(subFeePortion);
|
||||||
|
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
}
|
||||||
|
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||||
|
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
|
||||||
|
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||||
|
}
|
||||||
|
return transactionAmountRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For late repayments
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Money handleTransactionThatIsALateRepaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
final List<LoanRepaymentScheduleInstallment> installments, final LoanTransaction loanTransaction,
|
||||||
|
final Money transactionAmountUnprocessed, List<LoanTransactionToRepaymentScheduleMapping> transactionMappings,
|
||||||
|
Set<LoanCharge> charges) {
|
||||||
|
|
||||||
|
return handleTransactionThatIsOnTimePaymentOfInstallment(currentInstallment, loanTransaction, transactionAmountUnprocessed,
|
||||||
|
transactionMappings, charges);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For normal on-time repayments
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected Money handleTransactionThatIsOnTimePaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings, Set<LoanCharge> charges) {
|
||||||
|
|
||||||
|
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||||
|
|
||||||
|
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||||
|
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||||
|
Money principalPortion = Money.zero(currency);
|
||||||
|
Money interestPortion = Money.zero(currency);
|
||||||
|
Money feeChargesPortion = Money.zero(currency);
|
||||||
|
Money penaltyChargesPortion = Money.zero(currency);
|
||||||
|
|
||||||
|
if (loanTransaction.isChargesWaiver()) {
|
||||||
|
penaltyChargesPortion = currentInstallment.waivePenaltyChargesComponent(transactionDate,
|
||||||
|
loanTransaction.getPenaltyChargesPortion(currency));
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
|
||||||
|
feeChargesPortion = currentInstallment.waiveFeeChargesComponent(transactionDate,
|
||||||
|
loanTransaction.getFeeChargesPortion(currency));
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
|
||||||
|
} else if (loanTransaction.isInterestWaiver()) {
|
||||||
|
interestPortion = currentInstallment.waiveInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
} else if (loanTransaction.isChargePayment()) {
|
||||||
|
if (loanTransaction.isPenaltyPayment()) {
|
||||||
|
penaltyChargesPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
} else {
|
||||||
|
feeChargesPortion = currentInstallment.payFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
} else {
|
||||||
|
// Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee
|
||||||
|
boolean ignoreDueDateCheck = false;
|
||||||
|
boolean rerun = false;
|
||||||
|
|
||||||
|
List<LoanCharge> orderedLoanChargesByDueDate = charges.stream().filter(LoanCharge::isActive).filter(LoanCharge::isNotFullyPaid)
|
||||||
|
.filter(loanCharge -> loanCharge.getEffectiveDueDate() == null
|
||||||
|
|| !loanCharge.getEffectiveDueDate().isAfter(transactionDate))
|
||||||
|
.sorted(LoanChargeEffectiveDueDateComparator.INSTANCE).toList();
|
||||||
|
Money calculatedPenaltyCharge = Money.zero(currency);
|
||||||
|
Money calculatedFeeCharge = Money.zero(currency);
|
||||||
|
// Calculate the amount of due charges
|
||||||
|
for (LoanCharge charge : orderedLoanChargesByDueDate) {
|
||||||
|
if (charge.isPenaltyCharge()) {
|
||||||
|
calculatedPenaltyCharge = calculatedPenaltyCharge.add(charge.getAmount(currency));
|
||||||
|
} else {
|
||||||
|
calculatedFeeCharge = calculatedFeeCharge.add(charge.getAmount(currency));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
do {
|
||||||
|
Money subPenaltyPortion;
|
||||||
|
if (!ignoreDueDateCheck) {
|
||||||
|
if (calculatedPenaltyCharge.isGreaterThan(transactionAmountRemaining)) {
|
||||||
|
calculatedPenaltyCharge = transactionAmountRemaining;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
calculatedPenaltyCharge = transactionAmountUnprocessed;
|
||||||
|
}
|
||||||
|
subPenaltyPortion = currentInstallment.payPenaltyChargesComponent(transactionDate, calculatedPenaltyCharge);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subPenaltyPortion);
|
||||||
|
penaltyChargesPortion = penaltyChargesPortion.add(subPenaltyPortion);
|
||||||
|
|
||||||
|
Money subInterestPortion;
|
||||||
|
if (ignoreDueDateCheck || !transactionDate.isBefore(currentInstallment.getDueDate())) {
|
||||||
|
subInterestPortion = currentInstallment.payInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subInterestPortion);
|
||||||
|
interestPortion = interestPortion.add(subInterestPortion);
|
||||||
|
}
|
||||||
|
|
||||||
|
Money subPrincipalPortion = currentInstallment.payPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subPrincipalPortion);
|
||||||
|
principalPortion = principalPortion.add(subPrincipalPortion);
|
||||||
|
|
||||||
|
Money subFeePortion;
|
||||||
|
if (!ignoreDueDateCheck) {
|
||||||
|
if (calculatedFeeCharge.isGreaterThan(transactionAmountRemaining)) {
|
||||||
|
calculatedFeeCharge = transactionAmountRemaining;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
calculatedFeeCharge = transactionAmountUnprocessed;
|
||||||
|
}
|
||||||
|
subFeePortion = currentInstallment.payFeeChargesComponent(transactionDate, calculatedFeeCharge);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(subFeePortion);
|
||||||
|
feeChargesPortion = feeChargesPortion.add(subFeePortion);
|
||||||
|
|
||||||
|
// If the transactionAmountRemaining is greater than zero, rerun the allocation without due date check
|
||||||
|
// to distribute the in advance portions
|
||||||
|
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||||
|
ignoreDueDateCheck = true;
|
||||||
|
}
|
||||||
|
rerun = !rerun;
|
||||||
|
} while (ignoreDueDateCheck && rerun);
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
}
|
||||||
|
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||||
|
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
|
||||||
|
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||||
|
}
|
||||||
|
return transactionAmountRemaining;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onLoanOverpayment(final LoanTransaction loanTransaction, final Money loanOverPaymentAmount) {
|
||||||
|
// TODO - KW - dont do anything with loan over-payment for now
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Money handleRefundTransactionPaymentOfInstallment(final LoanRepaymentScheduleInstallment currentInstallment,
|
||||||
|
final LoanTransaction loanTransaction, final Money transactionAmountUnprocessed,
|
||||||
|
List<LoanTransactionToRepaymentScheduleMapping> transactionMappings) {
|
||||||
|
|
||||||
|
final LocalDate transactionDate = loanTransaction.getTransactionDate();
|
||||||
|
final MonetaryCurrency currency = transactionAmountUnprocessed.getCurrency();
|
||||||
|
Money transactionAmountRemaining = transactionAmountUnprocessed;
|
||||||
|
Money principalPortion = Money.zero(currency);
|
||||||
|
Money interestPortion = Money.zero(currency);
|
||||||
|
Money feeChargesPortion = Money.zero(currency);
|
||||||
|
Money penaltyChargesPortion = Money.zero(currency);
|
||||||
|
|
||||||
|
principalPortion = currentInstallment.unpayPrincipalComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(principalPortion);
|
||||||
|
|
||||||
|
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||||
|
interestPortion = currentInstallment.unpayInterestComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(interestPortion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||||
|
feeChargesPortion = currentInstallment.unpayFeeChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(feeChargesPortion);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (transactionAmountRemaining.isGreaterThanZero()) {
|
||||||
|
penaltyChargesPortion = currentInstallment.unpayPenaltyChargesComponent(transactionDate, transactionAmountRemaining);
|
||||||
|
transactionAmountRemaining = transactionAmountRemaining.minus(penaltyChargesPortion);
|
||||||
|
}
|
||||||
|
loanTransaction.updateComponents(principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion);
|
||||||
|
if (principalPortion.plus(interestPortion).plus(feeChargesPortion).plus(penaltyChargesPortion).isGreaterThanZero()) {
|
||||||
|
transactionMappings.add(LoanTransactionToRepaymentScheduleMapping.createFrom(loanTransaction, currentInstallment,
|
||||||
|
principalPortion, interestPortion, feeChargesPortion, penaltyChargesPortion));
|
||||||
|
}
|
||||||
|
return transactionAmountRemaining;
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -21,7 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.starter;
|
|||||||
import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
|
import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
|
||||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
|
|
||||||
public class DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition extends PropertiesCondition {
|
public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition extends PropertiesCondition {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean matches(FineractProperties properties) {
|
protected boolean matches(FineractProperties properties) {
|
||||||
+31
@@ -0,0 +1,31 @@
|
|||||||
|
/**
|
||||||
|
* 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.starter;
|
||||||
|
|
||||||
|
import org.apache.fineract.infrastructure.core.condition.PropertiesCondition;
|
||||||
|
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||||
|
|
||||||
|
public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition extends PropertiesCondition {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean matches(FineractProperties properties) {
|
||||||
|
return properties.getLoan().getTransactionProcessor().getDuePenaltyInterestPrincipalFeeInAdvancePenaltyInterestPrincipalFee()
|
||||||
|
.isEnabled();
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-4
@@ -22,7 +22,8 @@ import java.util.List;
|
|||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.LoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.CreocoreLoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DueDateRespectiveLoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.EarlyPaymentLoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
|
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.HeavensFamilyLoanRepaymentScheduleTransactionProcessor;
|
||||||
@@ -80,9 +81,15 @@ public class LoanAccountAutoStarter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@Conditional(DueDateRespectiveLoanRepaymentScheduleTransactionProcessorCondition.class)
|
@Conditional(DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||||
public DueDateRespectiveLoanRepaymentScheduleTransactionProcessor dueDateRespectiveTransactionProcessor() {
|
public DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor duePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor() {
|
||||||
return new DueDateRespectiveLoanRepaymentScheduleTransactionProcessor();
|
return new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
@Conditional(DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||||
|
public DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor duePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor() {
|
||||||
|
return new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
|
|||||||
@@ -90,6 +90,7 @@ fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=${F
|
|||||||
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_PRINCIPAL_INTEREST_PENALTIES_FEES_ENABLED:true}
|
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_PRINCIPAL_INTEREST_PENALTIES_FEES_ENABLED:true}
|
||||||
fineract.loan.transactionprocessor.rbi-india.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_RBI_INDIA_ENABLED:true}
|
fineract.loan.transactionprocessor.rbi-india.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_RBI_INDIA_ENABLED:true}
|
||||||
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_ENABLED:true}
|
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_ENABLED:true}
|
||||||
|
fineract.loan.transactionprocessor.due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee.enabled=${FINERACT_LOAN_TRANSACTIONPROCESSOR_DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_ENABLED:true}
|
||||||
fineract.loan.transactionprocessor.error-not-found-fail=${FINERACT_LOAN_TRANSACTIONPROCESSOR_ERROR_NOT_FOUND_FAIL:true}
|
fineract.loan.transactionprocessor.error-not-found-fail=${FINERACT_LOAN_TRANSACTIONPROCESSOR_ERROR_NOT_FOUND_FAIL:true}
|
||||||
|
|
||||||
fineract.content.regex-whitelist-enabled=${FINERACT_CONTENT_REGEX_WHITELIST_ENABLED:true}
|
fineract.content.regex-whitelist-enabled=${FINERACT_CONTENT_REGEX_WHITELIST_ENABLED:true}
|
||||||
|
|||||||
@@ -125,4 +125,5 @@
|
|||||||
<include file="parts/0103_modify_parameter_json_column_custom_job_parameters.xml" relativeToChangelogFile="true" />
|
<include file="parts/0103_modify_parameter_json_column_custom_job_parameters.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0104_loan_product_add_repayment_overdue_days_config.xml" relativeToChangelogFile="true" />
|
<include file="parts/0104_loan_product_add_repayment_overdue_days_config.xml" relativeToChangelogFile="true" />
|
||||||
<include file="parts/0105_add_indices_loan_table.xml" relativeToChangelogFile="true" />
|
<include file="parts/0105_add_indices_loan_table.xml" relativeToChangelogFile="true" />
|
||||||
|
<include file="parts/0106_new_repayment_strategy.xml" relativeToChangelogFile="true" />
|
||||||
</databaseChangeLog>
|
</databaseChangeLog>
|
||||||
|
|||||||
+42
@@ -0,0 +1,42 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!--
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
-->
|
||||||
|
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
|
||||||
|
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||||
|
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
|
||||||
|
<changeSet author="fineract" id="1">
|
||||||
|
<insert tableName="r_enum_value">
|
||||||
|
<column name="enum_name" value="loan_transaction_strategy_id"/>
|
||||||
|
<column name="enum_id" valueNumeric="9"/>
|
||||||
|
<column name="enum_message_property" value="Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee"/>
|
||||||
|
<column name="enum_value" value="Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee"/>
|
||||||
|
<column name="enum_type" valueBoolean="false"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
<changeSet id="2" author="fineract">
|
||||||
|
<insert tableName="ref_loan_transaction_processing_strategy">
|
||||||
|
<column name="id" valueNumeric="9"/>
|
||||||
|
<column name="code" value="due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy"/>
|
||||||
|
<column name="name" value="Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee"/>
|
||||||
|
<column name="sort_order" valueNumeric="9"/>
|
||||||
|
</insert>
|
||||||
|
</changeSet>
|
||||||
|
</databaseChangeLog>
|
||||||
@@ -61,6 +61,7 @@ fineract.loan.transactionprocessor.interest-principal-penalties-fees.enabled=tru
|
|||||||
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=true
|
fineract.loan.transactionprocessor.principal-interest-penalties-fees.enabled=true
|
||||||
fineract.loan.transactionprocessor.rbi-india.enabled=true
|
fineract.loan.transactionprocessor.rbi-india.enabled=true
|
||||||
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=true
|
fineract.loan.transactionprocessor.due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest.enabled=true
|
||||||
|
fineract.loan.transactionprocessor.due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee.enabled=true
|
||||||
fineract.loan.transactionprocessor.error-not-found-fail=true
|
fineract.loan.transactionprocessor.error-not-found-fail=true
|
||||||
|
|
||||||
fineract.content.regex-whitelist-enabled=true
|
fineract.content.regex-whitelist-enabled=true
|
||||||
|
|||||||
+773
-11
@@ -22,24 +22,30 @@ import static org.junit.jupiter.api.Assertions.assertEquals;
|
|||||||
import static org.junit.jupiter.api.Assertions.assertNull;
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
import static org.junit.jupiter.api.Assertions.assertTrue;
|
import static org.junit.jupiter.api.Assertions.assertTrue;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import io.restassured.builder.RequestSpecBuilder;
|
import io.restassured.builder.RequestSpecBuilder;
|
||||||
import io.restassured.builder.ResponseSpecBuilder;
|
import io.restassured.builder.ResponseSpecBuilder;
|
||||||
import io.restassured.http.ContentType;
|
import io.restassured.http.ContentType;
|
||||||
import io.restassured.specification.RequestSpecification;
|
import io.restassured.specification.RequestSpecification;
|
||||||
import io.restassured.specification.ResponseSpecification;
|
import io.restassured.specification.ResponseSpecification;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import org.apache.fineract.client.models.BusinessDateRequest;
|
import org.apache.fineract.client.models.BusinessDateRequest;
|
||||||
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||||
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||||
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
|
||||||
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
import org.apache.fineract.integrationtests.common.BusinessDateHelper;
|
||||||
import org.apache.fineract.integrationtests.common.ClientHelper;
|
import org.apache.fineract.integrationtests.common.ClientHelper;
|
||||||
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
|
||||||
|
import org.apache.fineract.integrationtests.common.LoanRescheduleRequestHelper;
|
||||||
import org.apache.fineract.integrationtests.common.Utils;
|
import org.apache.fineract.integrationtests.common.Utils;
|
||||||
import org.apache.fineract.integrationtests.common.accounting.Account;
|
import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||||
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
|
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
|
||||||
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||||
|
import org.apache.fineract.integrationtests.common.loans.LoanRescheduleRequestTestBuilder;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
|
import org.apache.fineract.integrationtests.common.loans.LoanStatusChecker;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
import org.apache.fineract.integrationtests.common.loans.LoanTestLifecycleExtension;
|
||||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||||
@@ -57,6 +63,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
private RequestSpecification requestSpec;
|
private RequestSpecification requestSpec;
|
||||||
private BusinessDateHelper businessDateHelper;
|
private BusinessDateHelper businessDateHelper;
|
||||||
private LoanTransactionHelper loanTransactionHelper;
|
private LoanTransactionHelper loanTransactionHelper;
|
||||||
|
private LoanRescheduleRequestHelper loanRescheduleRequestHelper;
|
||||||
|
|
||||||
private AccountHelper accountHelper;
|
private AccountHelper accountHelper;
|
||||||
|
|
||||||
@@ -68,12 +75,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||||
this.requestSpec.header("Fineract-Platform-TenantId", "default");
|
this.requestSpec.header("Fineract-Platform-TenantId", "default");
|
||||||
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
||||||
this.loanTransactionHelper = new LoanTransactionHelper(this.requestSpec, this.responseSpec);
|
this.loanRescheduleRequestHelper = new LoanRescheduleRequestHelper(this.requestSpec, this.responseSpec);
|
||||||
this.businessDateHelper = new BusinessDateHelper();
|
this.businessDateHelper = new BusinessDateHelper();
|
||||||
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Scenario1:
|
// Scenario1:
|
||||||
|
// DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
|
||||||
// 1. Disburse the loan
|
// 1. Disburse the loan
|
||||||
// 2. Adding a partial repayment
|
// 2. Adding a partial repayment
|
||||||
// 3. Adding a charge
|
// 3. Adding a charge
|
||||||
@@ -97,11 +105,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", true));
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", true));
|
||||||
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, "01 January 2023", "01 January 2023");
|
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -176,6 +186,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scenario2:
|
// Scenario2:
|
||||||
|
// DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
|
||||||
// 1. Disburse the loan
|
// 1. Disburse the loan
|
||||||
// 2. Adding a partial repayment
|
// 2. Adding a partial repayment
|
||||||
// 3. Adding a charge
|
// 3. Adding a charge
|
||||||
@@ -206,11 +217,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
||||||
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, "01 January 2023", "01 January 2023");
|
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -290,6 +303,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scenario3:
|
// Scenario3:
|
||||||
|
// DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
|
||||||
// 1. Disburse the loan
|
// 1. Disburse the loan
|
||||||
// 2. Adding a partial repayment
|
// 2. Adding a partial repayment
|
||||||
// 3. Adding a charge
|
// 3. Adding a charge
|
||||||
@@ -311,11 +325,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
||||||
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, "01 January 2023", "01 January 2023");
|
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -405,6 +421,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scenario4:
|
// Scenario4:
|
||||||
|
// DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
|
||||||
// 1. Disburse the loan with 3 installments
|
// 1. Disburse the loan with 3 installments
|
||||||
// 2. Adding a charge but not due
|
// 2. Adding a charge but not due
|
||||||
// 2. Adding a repayment which fully pays 1st installment and partially the next
|
// 2. Adding a repayment which fully pays 1st installment and partially the next
|
||||||
@@ -425,11 +442,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
||||||
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
|
||||||
LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "3", "1", "3", "0",
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "3", "1", "3", "0",
|
||||||
LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, "01 January 2023", "01 January 2023");
|
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -490,6 +509,7 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Scenario5:
|
// Scenario5:
|
||||||
|
// DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY
|
||||||
// 1. Disburse the loan with 3 installments
|
// 1. Disburse the loan with 3 installments
|
||||||
// 2. Adding a charge but not due
|
// 2. Adding a charge but not due
|
||||||
// 2. Adding a repayment which fully pays 1st installment and partially the next
|
// 2. Adding a repayment which fully pays 1st installment and partially the next
|
||||||
@@ -511,11 +531,13 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "50", false));
|
||||||
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "3", "0",
|
||||||
LoanProductTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
LoanProductTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "3", "1", "3", "0",
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "3", "1", "3", "0",
|
||||||
LoanApplicationTestBuilder.DUE_DATE_RESPECTIVE_STRATEGY, "01 January 2023", "01 January 2023");
|
LoanApplicationTestBuilder.DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
@@ -635,6 +657,746 @@ public class DueDateRespectiveLoanRepaymentScheduleTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Scenario6:
|
||||||
|
// DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
|
||||||
|
// 1. Disburse the loan
|
||||||
|
// 2. Adding a snooze fee
|
||||||
|
// 3. Do partial repayment
|
||||||
|
// 3.1 Repay principal fully
|
||||||
|
// 3.2 Repay fee partially
|
||||||
|
@Test
|
||||||
|
public void scenario6() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "20", false));
|
||||||
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
|
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
|
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 2023", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
Integer firstChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), "25 January 2023", "20"));
|
||||||
|
Integer firstRepaymentId = (Integer) loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("1010.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(10.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scenario7:
|
||||||
|
// DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
|
||||||
|
// 1. Disburse the loan
|
||||||
|
// 2. Full repayment
|
||||||
|
// 3. Reverse repayment
|
||||||
|
// 3.1 Add NSF Fee
|
||||||
|
// 4. Partial repayment
|
||||||
|
@Test
|
||||||
|
public void scenario7() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.01.28").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "15", true));
|
||||||
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
|
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
|
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 2023", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
Integer firstRepaymentId = (Integer) loanTransactionHelper.makeRepayment("25 January 2023", Float.parseFloat("1000.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(0.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getClosedObligationsMet());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(0, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
PostLoansLoanIdTransactionsResponse reverseRepayment = loanTransactionHelper.reverseLoanTransaction((long) loanID,
|
||||||
|
(long) firstRepaymentId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
|
||||||
|
.transactionDate("28 January 2023").transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.01.31").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(1000.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertEquals(LocalDate.of(2023, 1, 28), response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getManuallyReversed());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(0, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer firstChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "28 January 2023", "15"));
|
||||||
|
Integer secondRepayment = (Integer) loanTransactionHelper.makeRepayment("31 January 2023", Float.parseFloat("1010.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(5.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(995.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(secondRepayment, response.getTransactions().get(2).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(2).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(2).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(2).getAmount());
|
||||||
|
assertEquals(995.0, response.getTransactions().get(2).getPrincipalPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(2).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getFeeChargesPortion());
|
||||||
|
assertEquals(5.0, response.getTransactions().get(2).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(2).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scenario8:
|
||||||
|
// DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
|
||||||
|
// 1. Disburse the loan
|
||||||
|
// 2. Snooze fee
|
||||||
|
// 3. Partial repayment
|
||||||
|
// 4. Reverse repayment
|
||||||
|
// 4.1 NSF Fee added
|
||||||
|
// 4. Partial repayment
|
||||||
|
@Test
|
||||||
|
public void scenario8() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "20", false));
|
||||||
|
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "15", true));
|
||||||
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
|
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
|
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 2023", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
final String requestJSON = new LoanRescheduleRequestTestBuilder().updateRescheduleFromDate("1 February 2023")
|
||||||
|
.updateAdjustedDueDate("01 March 2023").updateSubmittedOnDate("25 January 2023").updateGraceOnPrincipal(null)
|
||||||
|
.updateGraceOnInterest(null).updateExtraTerms(null).build(loanID.toString());
|
||||||
|
final HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("locale", "en");
|
||||||
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
|
map.put("approvedOnDate", "25 January 2023");
|
||||||
|
final String aproveRequestJSON = new Gson().toJson(map);
|
||||||
|
|
||||||
|
Integer loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
|
||||||
|
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(loanRescheduleRequestId, aproveRequestJSON);
|
||||||
|
|
||||||
|
Integer firstChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), "01 March 2023", "20"));
|
||||||
|
Integer firstRepaymentId = (Integer) loanTransactionHelper
|
||||||
|
.makeRepayment("10 February 2023", Float.parseFloat("1010.00"), loanID).get("resourceId");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(10.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
PostLoansLoanIdTransactionsResponse reverseRepayment = loanTransactionHelper.reverseLoanTransaction((long) loanID,
|
||||||
|
(long) firstRepaymentId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
|
||||||
|
.transactionDate("15 February 2023").transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
Integer secondChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "15 February 2023", "15"));
|
||||||
|
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(1035.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(1035.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertEquals(LocalDate.of(2023, 2, 15), response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getManuallyReversed());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer secondRepayment = (Integer) loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("15.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(1020.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(1020.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(secondRepayment, response.getTransactions().get(2).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(2).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(2).getType().getRepayment());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(2).getAmount());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getPrincipalPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(2).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getFeeChargesPortion());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(2).getOutstandingLoanBalance());
|
||||||
|
assertEquals(secondChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(2).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer thirdRepayment = (Integer) loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("1000.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(20.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(thirdRepayment, response.getTransactions().get(3).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(3).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(3).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(3).getType().getRepayment());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(3).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(3).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getOutstandingLoanBalance());
|
||||||
|
assertEquals(0, response.getTransactions().get(3).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer forthRepayment = (Integer) loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("10.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(10.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(forthRepayment, response.getTransactions().get(4).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(4).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(4).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(4).getType().getRepayment());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(4).getAmount());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(4).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(4).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(4).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Scenario9:
|
||||||
|
// DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY
|
||||||
|
// 1. Disburse the loan
|
||||||
|
// 2. Snooze fee
|
||||||
|
// 3. Partial repayment
|
||||||
|
// 4. Reverse repayment
|
||||||
|
// 4.1 NSF Fee added
|
||||||
|
// 4. Partial repayment
|
||||||
|
// 5. Reverse repayment
|
||||||
|
// 5.1 NSF Fee added
|
||||||
|
// 6. Partial repayment
|
||||||
|
@Test
|
||||||
|
public void scenario9() {
|
||||||
|
try {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.02.15").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
final Account assetAccount = this.accountHelper.createAssetAccount();
|
||||||
|
final Account incomeAccount = this.accountHelper.createIncomeAccount();
|
||||||
|
final Account expenseAccount = this.accountHelper.createExpenseAccount();
|
||||||
|
final Account overpaymentAccount = this.accountHelper.createLiabilityAccount();
|
||||||
|
|
||||||
|
Integer fee = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "20", false));
|
||||||
|
Integer penalty = ChargesHelper.createCharges(requestSpec, responseSpec,
|
||||||
|
ChargesHelper.getLoanSpecifiedDueDateJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_FLAT, "15", true));
|
||||||
|
final Integer loanProductID = createLoanProductWithNoAccountingNoInterest("1000", "1", "1", "0",
|
||||||
|
LoanProductTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
assetAccount, incomeAccount, expenseAccount, overpaymentAccount);
|
||||||
|
final Integer clientID = ClientHelper.createClient(requestSpec, responseSpec, "01 January 2023");
|
||||||
|
|
||||||
|
final Integer loanID = applyForLoanApplication(clientID, loanProductID, "1000", "1", "1", "1", "0",
|
||||||
|
LoanApplicationTestBuilder.DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY,
|
||||||
|
"01 January 2023", "01 January 2023");
|
||||||
|
|
||||||
|
HashMap<String, Object> loanStatusHashMap = LoanStatusChecker.getStatusOfLoan(requestSpec, responseSpec, loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsPending(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.approveLoan("01 January 2023", loanID);
|
||||||
|
LoanStatusChecker.verifyLoanIsApproved(loanStatusHashMap);
|
||||||
|
LoanStatusChecker.verifyLoanIsWaitingForDisbursal(loanStatusHashMap);
|
||||||
|
|
||||||
|
loanStatusHashMap = loanTransactionHelper.disburseLoanWithTransactionAmount("01 January 2023", loanID, "1000");
|
||||||
|
LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap);
|
||||||
|
|
||||||
|
final String requestJSON = new LoanRescheduleRequestTestBuilder().updateRescheduleFromDate("1 February 2023")
|
||||||
|
.updateAdjustedDueDate("01 March 2023").updateSubmittedOnDate("25 January 2023").updateGraceOnPrincipal(null)
|
||||||
|
.updateGraceOnInterest(null).updateExtraTerms(null).build(loanID.toString());
|
||||||
|
final HashMap<String, String> map = new HashMap<>();
|
||||||
|
map.put("locale", "en");
|
||||||
|
map.put("dateFormat", "dd MMMM yyyy");
|
||||||
|
map.put("approvedOnDate", "25 January 2023");
|
||||||
|
final String aproveRequestJSON = new Gson().toJson(map);
|
||||||
|
|
||||||
|
Integer loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
|
||||||
|
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(loanRescheduleRequestId, aproveRequestJSON);
|
||||||
|
|
||||||
|
Integer firstChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(fee), "01 March 2023", "20"));
|
||||||
|
Integer firstRepaymentId = (Integer) loanTransactionHelper
|
||||||
|
.makeRepayment("10 February 2023", Float.parseFloat("1010.00"), loanID).get("resourceId");
|
||||||
|
|
||||||
|
GetLoansLoanIdResponse response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(10.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
PostLoansLoanIdTransactionsResponse reverseRepayment = loanTransactionHelper.reverseLoanTransaction((long) loanID,
|
||||||
|
(long) firstRepaymentId, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
|
||||||
|
.transactionDate("15 February 2023").transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
Integer secondChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "15 February 2023", "15"));
|
||||||
|
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.03.01").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(1035.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(1035.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(firstRepaymentId, response.getTransactions().get(1).getId().intValue());
|
||||||
|
assertEquals(LocalDate.of(2023, 2, 15), response.getTransactions().get(1).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(1).getManuallyReversed());
|
||||||
|
assertTrue(response.getTransactions().get(1).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(1).getType().getRepayment());
|
||||||
|
assertEquals(1010.0, response.getTransactions().get(1).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(1).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getInterestPortion());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(1).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(1).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(1).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(1).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer secondRepayment = (Integer) loanTransactionHelper.makeRepayment("01 March 2023", Float.parseFloat("1030.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(5.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(secondRepayment, response.getTransactions().get(2).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(2).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(2).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(2).getType().getRepayment());
|
||||||
|
assertEquals(1030.0, response.getTransactions().get(2).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(2).getPrincipalPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(2).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getInterestPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(2).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(2).getOutstandingLoanBalance());
|
||||||
|
if (secondChargeId.equals(response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue())) {
|
||||||
|
assertEquals(secondChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(1).getChargeId().intValue());
|
||||||
|
} else {
|
||||||
|
assertEquals(secondChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(1).getChargeId().intValue());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(2).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
}
|
||||||
|
assertEquals(2, response.getTransactions().get(2).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.03.07").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
PostLoansLoanIdTransactionsResponse secondReverseRepayment = loanTransactionHelper.reverseLoanTransaction((long) loanID,
|
||||||
|
(long) secondRepayment, new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat("dd MMMM yyyy")
|
||||||
|
.transactionDate("07 March 2023").transactionAmount(0.0).locale("en"));
|
||||||
|
|
||||||
|
Integer thirdChargeId = loanTransactionHelper.addChargesForLoan(loanID,
|
||||||
|
LoanTransactionHelper.getSpecifiedDueDateChargesForLoanAsJSON(String.valueOf(penalty), "07 March 2023", "15"));
|
||||||
|
|
||||||
|
businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BusinessDateType.BUSINESS_DATE.getName())
|
||||||
|
.date("2023.03.08").dateFormat("yyyy.MM.dd").locale("en"));
|
||||||
|
|
||||||
|
Integer thirdRepayment = (Integer) loanTransactionHelper.makeRepayment("08 March 2023", Float.parseFloat("15.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(1035.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(1035.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
|
||||||
|
|
||||||
|
assertEquals(thirdRepayment, response.getTransactions().get(3).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(3).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(3).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(3).getType().getRepayment());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(3).getAmount());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getPrincipalPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(3).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getInterestPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(3).getFeeChargesPortion());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(3).getOutstandingLoanBalance());
|
||||||
|
assertEquals(secondChargeId, response.getTransactions().get(3).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(3).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer forthRepayment = (Integer) loanTransactionHelper.makeRepayment("08 March 2023", Float.parseFloat("1015.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(20.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
|
||||||
|
|
||||||
|
assertEquals(forthRepayment, response.getTransactions().get(4).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(4).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(4).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(4).getType().getRepayment());
|
||||||
|
assertEquals(1015.0, response.getTransactions().get(4).getAmount());
|
||||||
|
assertEquals(1000.0, response.getTransactions().get(4).getPrincipalPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getInterestPortion());
|
||||||
|
assertEquals(15.0, response.getTransactions().get(4).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(4).getOutstandingLoanBalance());
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(4).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
assertEquals(1, response.getTransactions().get(4).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
Integer fifthRepayment = (Integer) loanTransactionHelper.makeRepayment("08 March 2023", Float.parseFloat("10.00"), loanID)
|
||||||
|
.get("resourceId");
|
||||||
|
|
||||||
|
response = loanTransactionHelper.getLoanDetails((long) loanID);
|
||||||
|
assertEquals(10.0, response.getSummary().getTotalOutstanding());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getTotalOutstanding());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesDue());
|
||||||
|
assertEquals(20.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesDue());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalDue());
|
||||||
|
assertEquals(1000.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(1).getPrincipalOutstanding());
|
||||||
|
assertTrue(response.getStatus().getActive());
|
||||||
|
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getFeeChargesOutstanding());
|
||||||
|
assertEquals(15.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesDue());
|
||||||
|
assertEquals(5.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesPaid());
|
||||||
|
assertEquals(10.0, response.getRepaymentSchedule().getPeriods().get(2).getPenaltyChargesOutstanding());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalDue());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalPaid());
|
||||||
|
assertEquals(0.0, response.getRepaymentSchedule().getPeriods().get(2).getPrincipalOutstanding());
|
||||||
|
|
||||||
|
assertEquals(fifthRepayment, response.getTransactions().get(5).getId().intValue());
|
||||||
|
assertNull(response.getTransactions().get(5).getReversedOnDate());
|
||||||
|
assertTrue(response.getTransactions().get(5).getTransactionRelations().isEmpty());
|
||||||
|
assertTrue(response.getTransactions().get(5).getType().getRepayment());
|
||||||
|
assertEquals(10.0, response.getTransactions().get(5).getAmount());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(5).getPrincipalPortion());
|
||||||
|
assertEquals(5.0, response.getTransactions().get(5).getPenaltyChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(5).getOverpaymentPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(5).getInterestPortion());
|
||||||
|
assertEquals(5.0, response.getTransactions().get(5).getFeeChargesPortion());
|
||||||
|
assertEquals(0.0, response.getTransactions().get(5).getOutstandingLoanBalance());
|
||||||
|
if (firstChargeId.equals(response.getTransactions().get(5).getLoanChargePaidByList().get(0).getChargeId().intValue())) {
|
||||||
|
assertEquals(thirdChargeId, response.getTransactions().get(5).getLoanChargePaidByList().get(1).getChargeId().intValue());
|
||||||
|
} else {
|
||||||
|
assertEquals(firstChargeId, response.getTransactions().get(5).getLoanChargePaidByList().get(1).getChargeId().intValue());
|
||||||
|
assertEquals(thirdChargeId, response.getTransactions().get(5).getLoanChargePaidByList().get(0).getChargeId().intValue());
|
||||||
|
}
|
||||||
|
assertEquals(2, response.getTransactions().get(5).getLoanChargePaidByList().size());
|
||||||
|
|
||||||
|
} finally {
|
||||||
|
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.FALSE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String principal,
|
private Integer applyForLoanApplication(final Integer clientID, final Integer loanProductID, final String principal,
|
||||||
final String loanTermFrequency, final String repaymentAfterEvery, final String numberOfRepayments, final String interestRate,
|
final String loanTermFrequency, final String repaymentAfterEvery, final String numberOfRepayments, final String interestRate,
|
||||||
final String repaymentStrategy, final String expectedDisbursementDate, final String submittedOnDate) {
|
final String repaymentStrategy, final String expectedDisbursementDate, final String submittedOnDate) {
|
||||||
|
|||||||
+2
-1
@@ -42,7 +42,8 @@ public class LoanApplicationTestBuilder {
|
|||||||
public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
|
public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
|
||||||
public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";
|
public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";
|
||||||
public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy";
|
public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy";
|
||||||
public static final String DUE_DATE_RESPECTIVE_STRATEGY = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
public static final String DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
||||||
|
public static final String DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY = "due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
|
||||||
|
|
||||||
private String externalId = null;
|
private String externalId = null;
|
||||||
private String principal = "10,000";
|
private String principal = "10,000";
|
||||||
|
|||||||
+3
-1
@@ -42,7 +42,9 @@ public class LoanProductTestBuilder {
|
|||||||
private static final String FLAT_BALANCE = "1";
|
private static final String FLAT_BALANCE = "1";
|
||||||
public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
|
public static final String DEFAULT_STRATEGY = "mifos-standard-strategy";
|
||||||
public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy";
|
public static final String INTEREST_PRINCIPAL_PENALTIES_FEES_ORDER_STRATEGY = "interest-principal-penalties-fees-order-strategy";
|
||||||
public static final String DUE_DATE_RESPECTIVE_STRATEGY = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
public static final String DUE_PENALTY_FEE_INTEREST_PRINCIPAL_IN_ADVANCE_PRINCIPAL_PENALTY_FEE_INTEREST_STRATEGY = "due-penalty-fee-interest-principal-in-advance-principal-penalty-fee-interest-strategy";
|
||||||
|
public static final String DUE_PENALTY_INTEREST_PRINCIPAL_FEE_IN_ADVANCE_PENALTY_INTEREST_PRINCIPAL_FEE_STRATEGY = "due-penalty-interest-principal-fee-in-advance-penalty-interest-principal-fee-strategy";
|
||||||
|
|
||||||
// private static final String HEAVENS_FAMILY_STRATEGY ="heavensfamily-strategy";
|
// private static final String HEAVENS_FAMILY_STRATEGY ="heavensfamily-strategy";
|
||||||
// private static final String CREO_CORE_STRATEGY ="creocore-strategy";
|
// private static final String CREO_CORE_STRATEGY ="creocore-strategy";
|
||||||
public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";
|
public static final String RBI_INDIA_STRATEGY = "rbi-india-strategy";
|
||||||
|
|||||||
Reference in New Issue
Block a user