Merge pull request #1346 from fynmanoj/FINERACT-1151-fix

FINERACT-1151-fix
This commit is contained in:
Avik Ganguly
2020-09-25 13:58:09 +05:30
committed by GitHub
7 changed files with 151 additions and 1 deletions
@@ -359,4 +359,52 @@ public class LoanRescheduleOnDecliningBalanceLoanTest {
}
@Test
public void testCreateLoanRescheduleRequestWithMultpleInterestAppropriation() {
// create all required entities
this.createRequiredEntities();
this.createAndApproveLoanRescheduleRequestForInterestAppropriation();
this.createAndApproveLoanRescheduleRequestForSecondInterestAppropriation();
}
/**
* create new loan reschedule request
**/
private void createAndApproveLoanRescheduleRequestForSecondInterestAppropriation() {
LOG.info(
"---------------------------------CREATING LOAN RESCHEDULE REQUEST FOR INTEREST APPROPRIATTION-------------------------------------");
final String requestJSON = new LoanRescheduleRequestTestBuilder().updateGraceOnPrincipal(null).updateGraceOnInterest(null)
.updateExtraTerms(null).updateRescheduleFromDate("04 December 2015").updateAdjustedDueDate("04 June 2016")
.updateRecalculateInterest(true).build(this.loanId.toString());
this.loanRescheduleRequestId = this.loanRescheduleRequestHelper.createLoanRescheduleRequest(requestJSON);
this.loanRescheduleRequestHelper.verifyCreationOfLoanRescheduleRequest(this.loanRescheduleRequestId);
LOG.info("Successfully created loan reschedule request (ID: {} )", this.loanRescheduleRequestId);
final String aproveRequestJSON = new LoanRescheduleRequestTestBuilder().getApproveLoanRescheduleRequestJSON();
this.loanRescheduleRequestHelper.approveLoanRescheduleRequest(this.loanRescheduleRequestId, aproveRequestJSON);
final HashMap response = (HashMap) this.loanRescheduleRequestHelper.getLoanRescheduleRequest(loanRescheduleRequestId, "statusEnum");
assertTrue((Boolean) response.get("approved"));
LOG.info("Successfully approved loan reschedule request (ID: {})", this.loanRescheduleRequestId);
final Map repaymentSchedule = (Map) this.loanTransactionHelper.getLoanDetail(requestSpec, generalResponseSpec, loanId,
"repaymentSchedule");
final ArrayList periods = (ArrayList) repaymentSchedule.get("periods");
HashMap period = (HashMap) periods.get(7);
Float totalDueForPeriod = (Float) period.get("totalDueForPeriod");
final HashMap loanSummary = this.loanTransactionHelper.getLoanSummary(requestSpec, generalResponseSpec, loanId);
final Float totalExpectedRepayment = (Float) loanSummary.get("totalExpectedRepayment");
assertEquals(12187, totalDueForPeriod.intValue(), "EXPECTED REPAYMENT in Second Reschedule is NOK");
assertEquals(130750, totalExpectedRepayment.intValue(), "TOTAL EXPECTED in Second Reschedule REPAYMENT is NOK");
LOG.info("Successfully approved loan reschedule request (ID: {})", this.loanRescheduleRequestId);
}
}
@@ -82,6 +82,9 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
@Column(name = "accrual_interest_derived", scale = 6, precision = 19, nullable = true)
private BigDecimal interestAccrued;
@Column(name = "reschedule_interest_portion", scale = 6, precision = 19, nullable = true)
private BigDecimal rescheduleInterestPortion;
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
private BigDecimal feeChargesCharged;
@@ -139,6 +142,24 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
this.obligationsMet = false;
}
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
final Set<LoanInterestRecalcualtionAdditionalDetails> compoundingDetails, final BigDecimal rescheduleInterestPortion) {
this.loan = loan;
this.installmentNumber = installmentNumber;
this.fromDate = fromDate.toDateTimeAtStartOfDay().toDate();
this.dueDate = dueDate.toDateTimeAtStartOfDay().toDate();
this.principal = defaultToNullIfZero(principal);
this.interestCharged = defaultToNullIfZero(interest);
this.feeChargesCharged = defaultToNullIfZero(feeCharges);
this.penaltyCharges = defaultToNullIfZero(penaltyCharges);
this.obligationsMet = false;
this.recalculatedInterestComponent = recalculatedInterestComponent;
this.loanCompoundingDetails = compoundingDetails;
this.rescheduleInterestPortion = rescheduleInterestPortion;
}
public LoanRepaymentScheduleInstallment(final Loan loan, final Integer installmentNumber, final LocalDate fromDate,
final LocalDate dueDate, final BigDecimal principal, final BigDecimal interest, final BigDecimal feeCharges,
final BigDecimal penaltyCharges, final boolean recalculatedInterestComponent,
@@ -807,4 +828,13 @@ public final class LoanRepaymentScheduleInstallment extends AbstractAuditableCus
return getPenaltyChargesPaid(currency).plus(getFeeChargesPaid(currency)).plus(getInterestPaid(currency))
.plus(getPrincipalCompleted(currency));
}
public BigDecimal getRescheduleInterestPortion() {
return rescheduleInterestPortion;
}
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
this.rescheduleInterestPortion = rescheduleInterestPortion;
}
}
@@ -397,6 +397,7 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
for (LoanScheduleModelPeriod installment : (List<LoanScheduleModelPeriod>) periods) {
if (!installment.isEMIFixedSpecificToInstallment()) {
installment.addInterestAmount(interestFraction);
installment.setRescheduleInterestPortion(interestFraction.getAmount());
interestTobeApproppriated = interestTobeApproppriated.minus(interestFraction);
}
}
@@ -404,6 +405,11 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
if (interestTobeApproppriated.isGreaterThanZero()) {
lastInstallment.addInterestAmount(interestTobeApproppriated);
BigDecimal rescheduleInterestPortion = BigDecimal.ZERO;
if (lastInstallment.rescheduleInterestPortion() != null) {
rescheduleInterestPortion = lastInstallment.rescheduleInterestPortion();
}
lastInstallment.setRescheduleInterestPortion(rescheduleInterestPortion.add(interestTobeApproppriated.getAmount()));
}
scheduleParams.addTotalRepaymentExpected(loanApplicationTerms.getInterestTobeApproppriated());
scheduleParams.addTotalCumulativeInterest(loanApplicationTerms.getInterestTobeApproppriated());
@@ -2385,6 +2391,24 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
loanRepaymentScheduleTransactionProcessor, scheduleTillDate, applyInterestRecalculation);
periods.clear();
}
BigDecimal rescheuleInterestPortionTobeRetained = BigDecimal.ZERO;
for (LoanRepaymentScheduleInstallment retainedInstallment : retainedInstallments) {
if (retainedInstallment.getRescheduleInterestPortion() != null) {
rescheuleInterestPortionTobeRetained = rescheuleInterestPortionTobeRetained
.add(retainedInstallment.getRescheduleInterestPortion());
}
}
BigDecimal rescheuleInterestPortionTotal = BigDecimal.ZERO;
for (LoanRepaymentScheduleInstallment inst : loan.getRepaymentScheduleInstallments()) {
if (inst.getRescheduleInterestPortion() != null) {
rescheuleInterestPortionTotal = rescheuleInterestPortionTotal.add(inst.getRescheduleInterestPortion());
}
}
BigDecimal rescheuleInterestPortionTobeAppropriated = rescheuleInterestPortionTotal.subtract(rescheuleInterestPortionTobeRetained);
loanApplicationTerms.setInterestTobeApproppriated(Money.of(loan.getCurrency(), rescheuleInterestPortionTobeAppropriated));
LoanScheduleModel loanScheduleModel = generate(mc, loanApplicationTerms, loan.charges(), holidayDetailDTO, loanScheduleParams);
for (LoanScheduleModelPeriod loanScheduleModelPeriod : loanScheduleModel.getPeriods()) {
@@ -2589,7 +2613,8 @@ public abstract class AbstractLoanScheduleGenerator implements LoanScheduleGener
scheduledLoanInstallment.periodFromDate(), scheduledLoanInstallment.periodDueDate(),
scheduledLoanInstallment.principalDue(), scheduledLoanInstallment.interestDue(),
scheduledLoanInstallment.feeChargesDue(), scheduledLoanInstallment.penaltyChargesDue(),
scheduledLoanInstallment.isRecalculatedInterestComponent(), scheduledLoanInstallment.getLoanCompoundingDetails());
scheduledLoanInstallment.isRecalculatedInterestComponent(), scheduledLoanInstallment.getLoanCompoundingDetails(),
scheduledLoanInstallment.rescheduleInterestPortion());
installments.add(installment);
}
return installment;
@@ -138,4 +138,14 @@ public final class LoanScheduleModelDisbursementPeriod implements LoanScheduleMo
public boolean isEMIFixedSpecificToInstallment() {
return isEMIFixedSpecificToInstallment;
}
@Override
public BigDecimal rescheduleInterestPortion() {
return null;
}
@Override
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
return;
}
}
@@ -58,4 +58,8 @@ public interface LoanScheduleModelPeriod {
void setEMIFixedSpecificToInstallmentTrue();
boolean isEMIFixedSpecificToInstallment();
BigDecimal rescheduleInterestPortion();
void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion);
}
@@ -43,6 +43,7 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
private final boolean recalculatedInterestComponent;
private final Set<LoanInterestRecalcualtionAdditionalDetails> loanCompoundingDetails = new HashSet<>();
private boolean isEMIFixedSpecificToInstallment = false;
BigDecimal rescheduleInterestPortion;
public static LoanScheduleModelRepaymentPeriod repayment(final int periodNumber, final LocalDate startDate,
final LocalDate scheduledDueDate, final Money principalDue, final Money outstandingLoanBalance, final Money interestDue,
@@ -172,4 +173,14 @@ public final class LoanScheduleModelRepaymentPeriod implements LoanScheduleModel
public void setEMIFixedSpecificToInstallmentTrue() {
this.isEMIFixedSpecificToInstallment = true;
}
@Override
public void setRescheduleInterestPortion(BigDecimal rescheduleInterestPortion) {
this.rescheduleInterestPortion = rescheduleInterestPortion;
}
@Override
public BigDecimal rescheduleInterestPortion() {
return this.rescheduleInterestPortion;
}
}
@@ -0,0 +1,22 @@
--
-- 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.
--
alter table m_loan_repayment_schedule
add column `reschedule_interest_portion` decimal(19,6) DEFAULT NULL after `accrual_interest_derived`;