FINERACT-2181: Fix Consult Loan repayment schedule with disbursement charge using interest
This commit is contained in:
committed by
Arnold Gálovics
parent
f2efad40a6
commit
9026fb9546
+2
-2
@@ -201,8 +201,8 @@ public class LoanCharge extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
this.externalId = externalId;
|
||||
}
|
||||
|
||||
private void populateDerivedFields(final BigDecimal amountPercentageAppliedTo, final BigDecimal chargeAmount,
|
||||
Integer numberOfRepayments, BigDecimal loanCharge) {
|
||||
public void populateDerivedFields(final BigDecimal amountPercentageAppliedTo, final BigDecimal chargeAmount, Integer numberOfRepayments,
|
||||
BigDecimal loanCharge) {
|
||||
|
||||
switch (ChargeCalculationType.fromInt(this.chargeCalculation)) {
|
||||
case INVALID:
|
||||
|
||||
+2
-2
@@ -36,7 +36,7 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
|
||||
private final Integer periodNumber;
|
||||
private final LocalDate disbursementDate;
|
||||
private final Money principalDisbursed;
|
||||
private final BigDecimal chargesDueAtTimeOfDisbursement;
|
||||
private BigDecimal chargesDueAtTimeOfDisbursement;
|
||||
private boolean isEMIFixedSpecificToInstallment = false;
|
||||
|
||||
public static LoanScheduleModelDisbursementPeriod disbursement(final LocalDate disbursementDate, final Money principalDisbursed,
|
||||
@@ -105,7 +105,7 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
|
||||
|
||||
@Override
|
||||
public void addLoanCharges(@SuppressWarnings("unused") BigDecimal feeCharge, @SuppressWarnings("unused") BigDecimal penaltyCharge) {
|
||||
return;
|
||||
this.chargesDueAtTimeOfDisbursement = this.chargesDueAtTimeOfDisbursement.add(feeCharge);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+38
-2
@@ -35,6 +35,7 @@ import java.time.temporal.ChronoField;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
@@ -110,6 +111,8 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplica
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGeneratorFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelDisbursementPeriod;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.VariableLoanScheduleFromApiJsonValidator;
|
||||
@@ -719,7 +722,9 @@ public class LoanScheduleAssembler {
|
||||
final List<Holiday> holidays, final WorkingDays workingDays, final JsonElement element,
|
||||
List<LoanDisbursementDetails> disbursementDetails) {
|
||||
|
||||
final Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element, disbursementDetails);
|
||||
Set<LoanCharge> loanCharges = this.loanChargeAssembler.fromParsedJson(element, disbursementDetails);
|
||||
final Set<LoanCharge> nonCompoundingCharges = validateDisbursementPercentageCharges(loanCharges);
|
||||
loanCharges.removeAll(nonCompoundingCharges);
|
||||
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
HolidayDetailDTO detailDTO = new HolidayDetailDTO(isHolidayEnabled, holidays, workingDays);
|
||||
@@ -742,7 +747,11 @@ public class LoanScheduleAssembler {
|
||||
loanApplicationTerms.getInterestMethod());
|
||||
}
|
||||
|
||||
return loanScheduleGenerator.generate(mc, loanApplicationTerms, loanCharges, detailDTO);
|
||||
LoanScheduleModel loanScheduleModel = loanScheduleGenerator.generate(mc, loanApplicationTerms, loanCharges, detailDTO);
|
||||
if (!nonCompoundingCharges.isEmpty()) {
|
||||
updateDisbursementWithCharges(loanScheduleModel.getPeriods(), nonCompoundingCharges);
|
||||
}
|
||||
return loanScheduleModel;
|
||||
}
|
||||
|
||||
public LoanScheduleModel assembleForInterestRecalculation(final LoanApplicationTerms loanApplicationTerms, final Long officeId,
|
||||
@@ -1542,4 +1551,31 @@ public class LoanScheduleAssembler {
|
||||
return Pair.of(loan, actualChanges);
|
||||
}
|
||||
|
||||
private Set<LoanCharge> validateDisbursementPercentageCharges(final Set<LoanCharge> loanCharges) {
|
||||
Set<LoanCharge> interestCharges = new HashSet<>();
|
||||
if (loanCharges != null) {
|
||||
for (final LoanCharge loanCharge : loanCharges) {
|
||||
if (loanCharge.isDisbursementCharge() && (loanCharge.getChargeCalculation().isPercentageOfInterest()
|
||||
|| loanCharge.getChargeCalculation().isPercentageOfAmountAndInterest())) {
|
||||
interestCharges.add(loanCharge);
|
||||
}
|
||||
}
|
||||
}
|
||||
return interestCharges;
|
||||
}
|
||||
|
||||
private void updateDisbursementWithCharges(final Collection<LoanScheduleModelPeriod> periods,
|
||||
final Set<LoanCharge> nonCompoundingCharges) {
|
||||
final BigDecimal totalInterest = periods.stream().filter(p -> p.isRepaymentPeriod()).map(LoanScheduleModelPeriod::interestDue)
|
||||
.reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
for (LoanScheduleModelPeriod loanScheduleModelPeriod : periods) {
|
||||
if (loanScheduleModelPeriod instanceof LoanScheduleModelDisbursementPeriod) {
|
||||
for (final LoanCharge loanCharge : nonCompoundingCharges) {
|
||||
loanCharge.populateDerivedFields(totalInterest, loanCharge.amountOrPercentage(), null, BigDecimal.ZERO);
|
||||
loanScheduleModelPeriod.addLoanCharges(loanCharge.getAmountOutstanding(), BigDecimal.ZERO);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+38
@@ -1047,6 +1047,44 @@ public class ClientLoanIntegrationTest extends BaseLoanIntegrationTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCharges_DISBURSEMENT_WITH_INTEREST() {
|
||||
|
||||
Calendar fourMonthsfromNowCalendar = Calendar.getInstance(Utils.getTimeZoneOfTenant());
|
||||
fourMonthsfromNowCalendar.add(Calendar.MONTH, -4);
|
||||
if (fourMonthsfromNowCalendar.get(Calendar.DAY_OF_MONTH) > 27) {
|
||||
fourMonthsfromNowCalendar.add(Calendar.DAY_OF_MONTH, 4);
|
||||
}
|
||||
|
||||
String fourMonthsfromNow = Utils.convertDateToURLFormat(fourMonthsfromNowCalendar);
|
||||
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC, RESPONSE_SPEC);
|
||||
ClientHelper.verifyClientCreatedOnServer(REQUEST_SPEC, RESPONSE_SPEC, clientID);
|
||||
final Integer loanProductID = createLoanProduct(false, NONE);
|
||||
|
||||
List<HashMap> charges = new ArrayList<>();
|
||||
Integer disbursementFee = ChargesHelper.createCharges(REQUEST_SPEC, RESPONSE_SPEC,
|
||||
ChargesHelper.getLoanDisbursementJSON(ChargesHelper.CHARGE_CALCULATION_TYPE_PERCENTAGE_INTEREST, "5"));
|
||||
addCharges(charges, disbursementFee, "5", null);
|
||||
|
||||
List<HashMap> collaterals = new ArrayList<>();
|
||||
final Integer loanID = applyForLoanApplicationWithPaymentStrategyAndPastMonth(clientID, loanProductID, charges, null, "1000",
|
||||
LoanApplicationTestBuilder.DEFAULT_STRATEGY, fourMonthsfromNow, collaterals);
|
||||
Assertions.assertNotNull(loanID);
|
||||
|
||||
LOAN_TRANSACTION_HELPER.approveLoan(fourMonthsfromNow, loanID);
|
||||
|
||||
String loanDetails = LOAN_TRANSACTION_HELPER.getLoanDetails(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
LOAN_TRANSACTION_HELPER.disburseLoanWithNetDisbursalAmount(fourMonthsfromNow, loanID,
|
||||
JsonPath.from(loanDetails).get("netDisbursalAmount").toString());
|
||||
|
||||
// check for disbursement fee: Principal 1,000 with 24% Annual Rate for 6 Months we have Total Interest of:
|
||||
// 120.00
|
||||
ArrayList<HashMap> loanSchedule = LOAN_TRANSACTION_HELPER.getLoanRepaymentSchedule(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
HashMap disbursementDetail = loanSchedule.get(0);
|
||||
// Disbursement Fee: 5% of 120.00 = 6.00
|
||||
validateNumberForEqual("6.00", String.valueOf(disbursementDetail.get("feeChargesDue")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoanCharges_DISBURSEMENT_WITH_TRANCHES() {
|
||||
final Integer clientID = ClientHelper.createClient(REQUEST_SPEC, RESPONSE_SPEC);
|
||||
|
||||
Reference in New Issue
Block a user