FINERACT-2190: Avoid recreation of loan repayment schedule periods
This commit is contained in:
committed by
Adam Saghy
parent
b9cfa470ff
commit
52c41b1471
-51
@@ -57,7 +57,6 @@ import java.util.List;
|
||||
import java.util.ListIterator;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.function.Predicate;
|
||||
@@ -112,7 +111,6 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Loa
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanApplicationTerms;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleGenerator;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AmortizationMethod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.CreditAllocationTransactionType;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.InterestCalculationPeriodMethod;
|
||||
@@ -610,8 +608,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
this.interestChargedFromDate = loanApplicationTerms.getInterestChargedFromDate();
|
||||
this.submittedOnDate = submittedOnDate != null ? submittedOnDate : DateUtils.getBusinessLocalDate();
|
||||
|
||||
updateLoanSchedule(loanScheduleModel);
|
||||
|
||||
updateSummaryWithTotalFeeChargesDueAtDisbursement(deriveSumTotalOfChargesDueAtDisbursement());
|
||||
|
||||
// Copy interest recalculation settings if interest recalculation is enabled
|
||||
@@ -1005,53 +1001,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
this.rates.addAll(loanRates);
|
||||
}
|
||||
|
||||
public void updateLoanSchedule(final LoanScheduleModel modifiedLoanSchedule) {
|
||||
this.repaymentScheduleInstallments.clear();
|
||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
|
||||
|
||||
if (scheduledLoanInstallment.isRepaymentPeriod() || scheduledLoanInstallment.isDownPaymentPeriod()) {
|
||||
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(this,
|
||||
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
|
||||
scheduledLoanInstallment.getLoanCompoundingDetails(), scheduledLoanInstallment.rescheduleInterestPortion(),
|
||||
scheduledLoanInstallment.isDownPaymentPeriod());
|
||||
addLoanRepaymentScheduleInstallment(installment);
|
||||
}
|
||||
}
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
public void updateLoanSchedule(final Collection<LoanRepaymentScheduleInstallment> installments) {
|
||||
List<LoanRepaymentScheduleInstallment> existingInstallments = new ArrayList<>(this.repaymentScheduleInstallments);
|
||||
repaymentScheduleInstallments.clear();
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
LoanRepaymentScheduleInstallment existingInstallment = findByInstallmentNumber(existingInstallments,
|
||||
installment.getInstallmentNumber());
|
||||
if (existingInstallment != null) {
|
||||
Set<LoanInstallmentCharge> existingCharges = existingInstallment.getInstallmentCharges();
|
||||
installment.getInstallmentCharges().addAll(existingCharges);
|
||||
existingCharges.forEach(c -> c.setInstallment(installment));
|
||||
existingInstallment.getInstallmentCharges().clear();
|
||||
}
|
||||
addLoanRepaymentScheduleInstallment(installment);
|
||||
}
|
||||
updateLoanScheduleDependentDerivedFields();
|
||||
updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
private LoanRepaymentScheduleInstallment findByInstallmentNumber(Collection<LoanRepaymentScheduleInstallment> installments,
|
||||
Integer installmentNumber) {
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
if (Objects.equals(installment.getInstallmentNumber(), installmentNumber)) {
|
||||
return installment;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void updateLoanScheduleDependentDerivedFields() {
|
||||
if (this.getLoanRepaymentScheduleInstallmentsSize() > 0) {
|
||||
this.expectedMaturityDate = determineExpectedMaturityDate();
|
||||
|
||||
+81
-25
@@ -38,10 +38,12 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
|
||||
import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDatedChecks;
|
||||
|
||||
@Getter
|
||||
@Setter
|
||||
@Entity
|
||||
@Table(name = "m_loan_repayment_schedule")
|
||||
public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDateTimeCustom<Long>
|
||||
@@ -60,67 +62,67 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
@Column(name = "duedate", nullable = false)
|
||||
private LocalDate dueDate;
|
||||
|
||||
@Column(name = "principal_amount", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "principal_amount", scale = 6, precision = 19)
|
||||
private BigDecimal principal;
|
||||
|
||||
@Column(name = "principal_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "principal_completed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal principalCompleted;
|
||||
|
||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "principal_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal principalWrittenOff;
|
||||
|
||||
@Column(name = "interest_amount", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "interest_amount", scale = 6, precision = 19)
|
||||
private BigDecimal interestCharged;
|
||||
|
||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "interest_completed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestPaid;
|
||||
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "interest_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestWaived;
|
||||
|
||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "interest_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestWrittenOff;
|
||||
|
||||
@Column(name = "accrual_interest_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "accrual_interest_derived", scale = 6, precision = 19)
|
||||
private BigDecimal interestAccrued;
|
||||
|
||||
@Column(name = "reschedule_interest_portion", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "reschedule_interest_portion", scale = 6, precision = 19)
|
||||
private BigDecimal rescheduleInterestPortion;
|
||||
|
||||
@Column(name = "fee_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "fee_charges_amount", scale = 6, precision = 19)
|
||||
private BigDecimal feeChargesCharged;
|
||||
|
||||
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "fee_charges_completed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal feeChargesPaid;
|
||||
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "fee_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal feeChargesWrittenOff;
|
||||
|
||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "fee_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal feeChargesWaived;
|
||||
|
||||
@Column(name = "accrual_fee_charges_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "accrual_fee_charges_derived", scale = 6, precision = 19)
|
||||
private BigDecimal feeAccrued;
|
||||
|
||||
@Column(name = "penalty_charges_amount", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "penalty_charges_amount", scale = 6, precision = 19)
|
||||
private BigDecimal penaltyCharges;
|
||||
|
||||
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "penalty_charges_completed_derived", scale = 6, precision = 19)
|
||||
private BigDecimal penaltyChargesPaid;
|
||||
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "penalty_charges_writtenoff_derived", scale = 6, precision = 19)
|
||||
private BigDecimal penaltyChargesWrittenOff;
|
||||
|
||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "penalty_charges_waived_derived", scale = 6, precision = 19)
|
||||
private BigDecimal penaltyChargesWaived;
|
||||
|
||||
@Column(name = "accrual_penalty_charges_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "accrual_penalty_charges_derived", scale = 6, precision = 19)
|
||||
private BigDecimal penaltyAccrued;
|
||||
|
||||
@Column(name = "total_paid_in_advance_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "total_paid_in_advance_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPaidInAdvance;
|
||||
|
||||
@Column(name = "total_paid_late_derived", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "total_paid_late_derived", scale = 6, precision = 19)
|
||||
private BigDecimal totalPaidLate;
|
||||
|
||||
@Column(name = "completed_derived", nullable = false)
|
||||
@@ -139,17 +141,17 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
// approach
|
||||
// https://blog.thepete.net/blog/2023/12/05/expand/contract-making-a-breaking-change-without-a-big-bang/
|
||||
@Setter
|
||||
@Column(name = "credits_amount", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "credits_amount", scale = 6, precision = 19)
|
||||
private BigDecimal creditedPrincipal;
|
||||
|
||||
@Setter
|
||||
@Column(name = "credited_interest", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "credited_interest", scale = 6, precision = 19)
|
||||
private BigDecimal creditedInterest;
|
||||
|
||||
@Column(name = "credited_fee", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "credited_fee", scale = 6, precision = 19)
|
||||
private BigDecimal creditedFee;
|
||||
|
||||
@Column(name = "credited_penalty", scale = 6, precision = 19, nullable = true)
|
||||
@Column(name = "credited_penalty", scale = 6, precision = 19)
|
||||
private BigDecimal creditedPenalty;
|
||||
|
||||
@Column(name = "is_down_payment", nullable = false)
|
||||
@@ -1068,4 +1070,58 @@ public class LoanRepaymentScheduleInstallment extends AbstractAuditableWithUTCDa
|
||||
MathUtil.nullToZero(MathUtil.add(getPrincipal(), getInterestCharged(), getFeeChargesCharged(), getPenaltyCharges())));
|
||||
}
|
||||
|
||||
public void copyFrom(final LoanScheduleModelPeriod period) {
|
||||
resetBalances();
|
||||
setFromDate(period.periodFromDate());
|
||||
setDueDate(period.periodDueDate());
|
||||
setPrincipal(period.principalDue());
|
||||
setInterestCharged(period.interestDue());
|
||||
setFeeChargesCharged(period.feeChargesDue());
|
||||
setPenaltyCharges(period.penaltyChargesDue());
|
||||
|
||||
setRecalculatedInterestComponent(period.isRecalculatedInterestComponent());
|
||||
if (getLoanCompoundingDetails() != null) {
|
||||
getLoanCompoundingDetails().clear();
|
||||
}
|
||||
if (period.getLoanCompoundingDetails() != null) {
|
||||
period.getLoanCompoundingDetails().forEach(lcd -> {
|
||||
lcd.setLoanRepaymentScheduleInstallment(this);
|
||||
getLoanCompoundingDetails().add(lcd);
|
||||
});
|
||||
}
|
||||
setRescheduleInterestPortion(period.rescheduleInterestPortion());
|
||||
setDownPayment(period.isDownPaymentPeriod());
|
||||
|
||||
setAdditional(false);
|
||||
setReAged(false);
|
||||
}
|
||||
|
||||
public void copyFrom(final LoanRepaymentScheduleInstallment installment) {
|
||||
setFromDate(installment.getFromDate());
|
||||
setDueDate(installment.getDueDate());
|
||||
|
||||
setPrincipal(installment.getPrincipal());
|
||||
setInterestCharged(installment.getInterestCharged());
|
||||
setFeeChargesCharged(installment.getFeeChargesCharged());
|
||||
setPenaltyCharges(installment.getPenaltyCharges());
|
||||
setRecalculatedInterestComponent(installment.isRecalculatedInterestComponent());
|
||||
if (getLoanCompoundingDetails() != null) {
|
||||
getLoanCompoundingDetails().clear();
|
||||
}
|
||||
if (installment.getLoanCompoundingDetails() != null) {
|
||||
installment.getLoanCompoundingDetails().forEach(lcd -> {
|
||||
lcd.setLoanRepaymentScheduleInstallment(this);
|
||||
getLoanCompoundingDetails().add(lcd);
|
||||
});
|
||||
}
|
||||
|
||||
Set<LoanInstallmentCharge> installmentCharges = installment.getInstallmentCharges();
|
||||
installmentCharges.forEach(c -> c.setInstallment(this));
|
||||
getInstallmentCharges().addAll(installmentCharges);
|
||||
|
||||
setAdditional(installment.isAdditional());
|
||||
setReAged(installment.isReAged());
|
||||
setDownPayment(installment.isDownPayment());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+10
-8
@@ -29,6 +29,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class LoanScheduleService {
|
||||
@@ -36,16 +37,17 @@ public class LoanScheduleService {
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanTransactionProcessingService loadTransactionProcessingService;
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
|
||||
/**
|
||||
* Ability to regenerate the repayment schedule based on the loans current details/state.
|
||||
*/
|
||||
public void regenerateRepaymentSchedule(final Loan loan, final ScheduleGeneratorDTO scheduleGeneratorDTO) {
|
||||
final LoanScheduleModel loanSchedule = loan.regenerateScheduleModel(scheduleGeneratorDTO);
|
||||
if (loanSchedule == null) {
|
||||
final LoanScheduleModel loanScheduleModel = loan.regenerateScheduleModel(scheduleGeneratorDTO);
|
||||
if (loanScheduleModel == null) {
|
||||
return;
|
||||
}
|
||||
loan.updateLoanSchedule(loanSchedule);
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleModel);
|
||||
final Set<LoanCharge> charges = loan.getActiveCharges();
|
||||
for (final LoanCharge loanCharge : charges) {
|
||||
if (!loanCharge.isWaived()) {
|
||||
@@ -80,15 +82,15 @@ public class LoanScheduleService {
|
||||
|
||||
public void regenerateRepaymentScheduleWithInterestRecalculation(final Loan loan, final ScheduleGeneratorDTO generatorDTO) {
|
||||
final LocalDate lastTransactionDate = loan.getLastUserTransactionDate();
|
||||
final LoanScheduleDTO loanSchedule = loadTransactionProcessingService.getRecalculatedSchedule(generatorDTO, loan);
|
||||
if (loanSchedule == null) {
|
||||
final LoanScheduleDTO loanScheduleDTO = loadTransactionProcessingService.getRecalculatedSchedule(generatorDTO, loan);
|
||||
if (loanScheduleDTO == null) {
|
||||
return;
|
||||
}
|
||||
// Either the installments got recalculated or the model
|
||||
if (loanSchedule.getInstallments() != null) {
|
||||
loan.updateLoanSchedule(loanSchedule.getInstallments());
|
||||
if (loanScheduleDTO.getInstallments() != null) {
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleDTO.getInstallments());
|
||||
} else {
|
||||
loan.updateLoanSchedule(loanSchedule.getLoanScheduleModel());
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleDTO.getLoanScheduleModel());
|
||||
}
|
||||
loan.setInterestRecalculatedOn(DateUtils.getBusinessLocalDate());
|
||||
final LocalDate lastRepaymentDate = loan.getLastRepaymentPeriodDueDate(true);
|
||||
|
||||
+91
@@ -0,0 +1,91 @@
|
||||
/**
|
||||
* 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.service.schedule;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class LoanScheduleComponent {
|
||||
|
||||
public void updateLoanSchedule(Loan loan, final LoanScheduleModel modifiedLoanSchedule) {
|
||||
final List<LoanScheduleModelPeriod> periods = modifiedLoanSchedule.getPeriods();
|
||||
for (final LoanScheduleModelPeriod scheduledLoanInstallment : modifiedLoanSchedule.getPeriods()) {
|
||||
if (scheduledLoanInstallment.isRepaymentPeriod() || scheduledLoanInstallment.isDownPaymentPeriod()) {
|
||||
LoanRepaymentScheduleInstallment existingInstallment = findByInstallmentNumber(loan.getRepaymentScheduleInstallments(),
|
||||
scheduledLoanInstallment.periodNumber());
|
||||
if (existingInstallment == null) {
|
||||
final LoanRepaymentScheduleInstallment installment = new LoanRepaymentScheduleInstallment(loan,
|
||||
scheduledLoanInstallment.periodNumber(), scheduledLoanInstallment.periodFromDate(),
|
||||
scheduledLoanInstallment.periodDueDate(), scheduledLoanInstallment.principalDue(),
|
||||
scheduledLoanInstallment.interestDue(), scheduledLoanInstallment.feeChargesDue(),
|
||||
scheduledLoanInstallment.penaltyChargesDue(), scheduledLoanInstallment.isRecalculatedInterestComponent(),
|
||||
scheduledLoanInstallment.getLoanCompoundingDetails(), scheduledLoanInstallment.rescheduleInterestPortion(),
|
||||
scheduledLoanInstallment.isDownPaymentPeriod());
|
||||
loan.addLoanRepaymentScheduleInstallment(installment);
|
||||
} else {
|
||||
existingInstallment.copyFrom(scheduledLoanInstallment);
|
||||
}
|
||||
}
|
||||
}
|
||||
// Review Installments removed
|
||||
loan.getRepaymentScheduleInstallments().removeIf(i -> !existInstallment(periods, i.getInstallmentNumber()));
|
||||
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
public void updateLoanSchedule(Loan loan, final List<LoanRepaymentScheduleInstallment> installments) {
|
||||
for (final LoanRepaymentScheduleInstallment installment : installments) {
|
||||
LoanRepaymentScheduleInstallment existingInstallment = findByInstallmentNumber(loan.getRepaymentScheduleInstallments(),
|
||||
installment.getInstallmentNumber());
|
||||
if (existingInstallment != null) {
|
||||
existingInstallment.copyFrom(installment);
|
||||
} else {
|
||||
loan.addLoanRepaymentScheduleInstallment(installment);
|
||||
}
|
||||
}
|
||||
// Review Installments removed
|
||||
loan.getRepaymentScheduleInstallments().removeIf(i -> !existInstallment(installments, i.getInstallmentNumber()));
|
||||
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
loan.updateLoanSummaryDerivedFields();
|
||||
}
|
||||
|
||||
private LoanRepaymentScheduleInstallment findByInstallmentNumber(final Collection<LoanRepaymentScheduleInstallment> installments,
|
||||
final Integer installmentNumber) {
|
||||
return installments.stream().filter(i -> installmentNumber.compareTo(i.getInstallmentNumber()) == 0).findFirst().orElse(null);
|
||||
}
|
||||
|
||||
private boolean existInstallment(final Collection<LoanRepaymentScheduleInstallment> installments, final Integer installmentNumber) {
|
||||
return installments.stream().anyMatch(i -> installmentNumber.compareTo(i.getInstallmentNumber()) == 0);
|
||||
}
|
||||
|
||||
private boolean existInstallment(final List<LoanScheduleModelPeriod> periods, final Integer installmentNumber) {
|
||||
return periods.stream().anyMatch(p -> p.periodNumber() != null && installmentNumber.compareTo(p.periodNumber()) == 0);
|
||||
}
|
||||
|
||||
}
|
||||
+5
-3
@@ -91,6 +91,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.Mon
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.InterestRefundService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.PeriodDueDetails;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
|
||||
@@ -114,13 +115,15 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
private final EMICalculator emiCalculator;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final InterestRefundService interestRefundService;
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
|
||||
public AdvancedPaymentScheduleTransactionProcessor(EMICalculator emiCalculator, LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
InterestRefundService interestRefundService, ExternalIdFactory externalIdFactory) {
|
||||
InterestRefundService interestRefundService, ExternalIdFactory externalIdFactory, LoanScheduleComponent loanSchedule) {
|
||||
super(externalIdFactory);
|
||||
this.emiCalculator = emiCalculator;
|
||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||
this.interestRefundService = interestRefundService;
|
||||
this.loanSchedule = loanSchedule;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -1460,8 +1463,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
}
|
||||
}
|
||||
|
||||
loan.updateLoanSchedule(installmentsUpToTransactionDate);
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
loanSchedule.updateLoanSchedule(loan, installmentsUpToTransactionDate);
|
||||
|
||||
if (transactionCtx instanceof ProgressiveTransactionCtx progressiveTransactionCtx && loan.isInterestRecalculationEnabled()) {
|
||||
updateRepaymentPeriodsAfterChargeOff(progressiveTransactionCtx, transactionDate, transactionsToBeReprocessed);
|
||||
|
||||
+3
-1
@@ -69,6 +69,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.TransactionCtx;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleProcessingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.data.ProgressiveLoanInterestScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.AllocationType;
|
||||
@@ -98,6 +99,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
private AdvancedPaymentScheduleTransactionProcessor underTest;
|
||||
private static final EMICalculator emiCalculator = Mockito.mock(EMICalculator.class);
|
||||
private static final LoanRepositoryWrapper loanRepositoryWrapper = Mockito.mock(LoanRepositoryWrapper.class);
|
||||
private static final LoanScheduleComponent loanSchedule = Mockito.mock(LoanScheduleComponent.class);
|
||||
|
||||
@BeforeAll
|
||||
public static void init() {
|
||||
@@ -112,7 +114,7 @@ class AdvancedPaymentScheduleTransactionProcessorTest {
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, null, null);
|
||||
underTest = new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, null, null, loanSchedule);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
ThreadLocalContextUtil.setActionContext(ActionContext.DEFAULT);
|
||||
|
||||
+6
-4
@@ -79,6 +79,7 @@ import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargeService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.useradministration.domain.AppUser;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
@@ -115,6 +116,7 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
private final LoanAccrualsProcessingService loanAccrualsProcessingService;
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
|
||||
/**
|
||||
* create a new instance of the LoanRescheduleRequest object from the JsonCommand object and persist
|
||||
@@ -423,14 +425,14 @@ public class LoanRescheduleRequestWritePlatformServiceImpl implements LoanResche
|
||||
loanApplicationTerms.getInterestMethod());
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine = null;
|
||||
loan.setHelpers(loanLifecycleStateMachine);
|
||||
final LoanScheduleDTO loanSchedule = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, loan,
|
||||
final LoanScheduleDTO loanScheduleDTO = loanScheduleGenerator.rescheduleNextInstallments(mathContext, loanApplicationTerms, loan,
|
||||
loanApplicationTerms.getHolidayDetailDTO(), loanRepaymentScheduleTransactionProcessor, rescheduleFromDate);
|
||||
|
||||
// Either the installments got recalculated or the model
|
||||
if (loanSchedule.getInstallments() != null) {
|
||||
loan.updateLoanSchedule(loanSchedule.getInstallments());
|
||||
if (loanScheduleDTO.getInstallments() != null) {
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleDTO.getInstallments());
|
||||
} else {
|
||||
loan.updateLoanSchedule(loanSchedule.getLoanScheduleModel());
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleDTO.getLoanScheduleModel());
|
||||
}
|
||||
loanAccrualsProcessingService.reprocessExistingAccruals(loan);
|
||||
loanChargeService.recalculateAllCharges(loan);
|
||||
|
||||
+6
-2
@@ -93,6 +93,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanSchedu
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleCalculationPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.mapper.LoanChargeMapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.mapper.LoanCollateralManagementMapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.LoanProductConstants;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProduct;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRelatedDetail;
|
||||
@@ -137,6 +138,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
|
||||
private final LoanDisbursementService loanDisbursementService;
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final LoanOfficerService loanOfficerService;
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
|
||||
@Override
|
||||
public Loan assembleFrom(final Long accountId) {
|
||||
@@ -293,6 +295,8 @@ public class LoanAssemblerImpl implements LoanAssembler {
|
||||
throw new IllegalStateException("No loan application exists for either a client or group (or both).");
|
||||
}
|
||||
|
||||
loanSchedule.updateLoanSchedule(loanApplication, loanScheduleModel);
|
||||
|
||||
copyAdvancedPaymentRulesIfApplicable(transactionProcessingStrategyCode, loanProduct, loanApplication);
|
||||
loanApplication.setHelpers(defaultLoanLifecycleStateMachine);
|
||||
// TODO: review
|
||||
@@ -858,8 +862,8 @@ public class LoanAssemblerImpl implements LoanAssembler {
|
||||
final JsonElement parsedQuery = this.fromApiJsonHelper.parse(command.json());
|
||||
final JsonQuery query = JsonQuery.from(command.json(), parsedQuery, this.fromApiJsonHelper);
|
||||
|
||||
final LoanScheduleModel loanSchedule = this.calculationPlatformService.calculateLoanSchedule(query, false);
|
||||
loan.updateLoanSchedule(loanSchedule);
|
||||
final LoanScheduleModel loanScheduleModel = this.calculationPlatformService.calculateLoanSchedule(query, false);
|
||||
loanSchedule.updateLoanSchedule(loan, loanScheduleModel);
|
||||
loanAccrualsProcessingService.reprocessExistingAccruals(loan);
|
||||
loanChargeService.recalculateAllCharges(loan);
|
||||
}
|
||||
|
||||
+4
-2
@@ -34,6 +34,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.imp
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.RBILoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ProgressiveLoanInterestRefundServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.calc.EMICalculator;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
@@ -118,8 +119,9 @@ public class LoanAccountAutoStarter {
|
||||
@Conditional(AdvancedPaymentScheduleTransactionProcessorCondition.class)
|
||||
public AdvancedPaymentScheduleTransactionProcessor advancedPaymentScheduleTransactionProcessor(EMICalculator emiCalculator,
|
||||
LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
@Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService, ExternalIdFactory externalIdFactory) {
|
||||
@Lazy ProgressiveLoanInterestRefundServiceImpl progressiveLoanInterestRefundService, ExternalIdFactory externalIdFactory,
|
||||
LoanScheduleComponent loanSchedule) {
|
||||
return new AdvancedPaymentScheduleTransactionProcessor(emiCalculator, loanRepositoryWrapper, progressiveLoanInterestRefundService,
|
||||
externalIdFactory);
|
||||
externalIdFactory, loanSchedule);
|
||||
}
|
||||
}
|
||||
|
||||
+6
-4
@@ -146,6 +146,7 @@ import org.apache.fineract.portfolio.loanaccount.service.ReplayedTransactionBusi
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReplayedTransactionBusinessEventServiceImpl;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.adjustment.LoanAdjustmentService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.schedule.LoanScheduleComponent;
|
||||
import org.apache.fineract.portfolio.loanproduct.domain.LoanProductRepository;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanDropdownReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanproduct.service.LoanProductReadPlatformService;
|
||||
@@ -240,14 +241,15 @@ public class LoanAccountConfiguration {
|
||||
LoanCollateralAssembler loanCollateralAssembler, LoanScheduleCalculationPlatformService calculationPlatformService,
|
||||
LoanDisbursementDetailsAssembler loanDisbursementDetailsAssembler, LoanChargeMapper loanChargeMapper,
|
||||
LoanCollateralManagementMapper loanCollateralManagementMapper, LoanAccrualsProcessingService loanAccrualsProcessingService,
|
||||
LoanDisbursementService loanDisbursementService, LoanChargeService loanChargeService, LoanOfficerService loanOfficerService) {
|
||||
LoanDisbursementService loanDisbursementService, LoanChargeService loanChargeService, LoanOfficerService loanOfficerService,
|
||||
LoanScheduleComponent loanSchedule) {
|
||||
return new LoanAssemblerImpl(fromApiJsonHelper, loanRepository, loanProductRepository, clientRepository, groupRepository,
|
||||
fundRepository, staffRepository, codeValueRepository, loanScheduleAssembler, loanChargeAssembler, collateralAssembler,
|
||||
loanRepaymentScheduleTransactionProcessorFactory, holidayRepository, configurationDomainService, workingDaysRepository,
|
||||
rateAssembler, defaultLoanLifecycleStateMachine, externalIdFactory, accountNumberFormatRepository, glimRepository,
|
||||
accountNumberGenerator, glimAccountInfoWritePlatformService, loanCollateralAssembler, calculationPlatformService,
|
||||
loanDisbursementDetailsAssembler, loanChargeMapper, loanCollateralManagementMapper, loanAccrualsProcessingService,
|
||||
loanDisbursementService, loanChargeService, loanOfficerService);
|
||||
loanDisbursementService, loanChargeService, loanOfficerService, loanSchedule);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@@ -461,8 +463,8 @@ public class LoanAccountConfiguration {
|
||||
@ConditionalOnMissingBean(LoanScheduleService.class)
|
||||
public LoanScheduleService loanScheduleService(LoanChargeService loanChargeService,
|
||||
ReprocessLoanTransactionsService reprocessLoanTransactionsService,
|
||||
LoanTransactionProcessingService loanTransactionProcessingService) {
|
||||
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanTransactionProcessingService);
|
||||
LoanTransactionProcessingService loanTransactionProcessingService, LoanScheduleComponent loanSchedule) {
|
||||
return new LoanScheduleService(loanChargeService, reprocessLoanTransactionsService, loanTransactionProcessingService, loanSchedule);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+6
-6
@@ -5310,8 +5310,8 @@ public class ClientLoanIntegrationTest extends BaseLoanIntegrationTest {
|
||||
|
||||
ArrayList<HashMap> loanSchedule = LOAN_TRANSACTION_HELPER.getLoanRepaymentSchedule(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
assertEquals(2, loanSchedule.size());
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(1000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||
assertEquals(1000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||
LocalDate targetDate = LocalDate.of(2022, 9, 7);
|
||||
@@ -5906,10 +5906,10 @@ public class ClientLoanIntegrationTest extends BaseLoanIntegrationTest {
|
||||
|
||||
ArrayList<HashMap> loanSchedule = LOAN_TRANSACTION_HELPER.getLoanRepaymentSchedule(REQUEST_SPEC, RESPONSE_SPEC, loanID);
|
||||
assertEquals(2, loanSchedule.size());
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(1000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||
assertEquals(1000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||
LocalDate targetDate = LocalDate.of(2022, 9, 7);
|
||||
|
||||
+8
-8
@@ -173,10 +173,10 @@ public class LoanSpecificDueDateChargeAfterMaturityTest extends BaseLoanIntegrat
|
||||
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||
assertEquals(2, loanSchedule.size());
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(10000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||
assertEquals(10000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||
targetDate = LocalDate.of(2011, 4, 5);
|
||||
@@ -306,10 +306,10 @@ public class LoanSpecificDueDateChargeAfterMaturityTest extends BaseLoanIntegrat
|
||||
|
||||
ArrayList<HashMap> loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec, loanID);
|
||||
assertEquals(2, loanSchedule.size());
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("feeChargesOutstanding"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesDue"));
|
||||
assertEquals(0.0f, loanSchedule.get(1).get("penaltyChargesOutstanding"));
|
||||
assertEquals(10000.0f, loanSchedule.get(1).get("totalDueForPeriod"));
|
||||
assertEquals(10000.0f, loanSchedule.get(1).get("totalOutstandingForPeriod"));
|
||||
|
||||
|
||||
+3
-3
@@ -844,7 +844,7 @@ public class SchedulerJobsTestResults extends IntegrationTest {
|
||||
ArrayList<HashMap> repaymentScheduleDataAfter = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
|
||||
loanID);
|
||||
|
||||
Assertions.assertEquals(0, (Integer) repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
Assertions.assertEquals(0.0f, repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
"Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job");
|
||||
|
||||
}
|
||||
@@ -1085,7 +1085,7 @@ public class SchedulerJobsTestResults extends IntegrationTest {
|
||||
this.schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
List<HashMap> repaymentScheduleDataAfter = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
|
||||
loanID);
|
||||
Assertions.assertEquals(0, (Integer) repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
Assertions.assertEquals(0.0f, repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
"Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job");
|
||||
|
||||
LocalDate lastBusinessDateBeforeFastForward = LocalDate.of(2019, 4, 2);
|
||||
@@ -1153,7 +1153,7 @@ public class SchedulerJobsTestResults extends IntegrationTest {
|
||||
this.schedulerJobHelper.executeAndAwaitJob(jobName);
|
||||
List<HashMap> repaymentScheduleDataAfter = this.loanTransactionHelper.getLoanRepaymentSchedule(requestSpec, responseSpec,
|
||||
loanID2);
|
||||
Assertions.assertEquals(0, (Integer) repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
Assertions.assertEquals(0.0f, repaymentScheduleDataAfter.get(1).get("penaltyChargesDue"),
|
||||
"Verifying From Penalty Charges due fot first Repayment after Successful completion of Scheduler Job");
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.COB_DATE, LocalDate.of(2020, 5, 3));
|
||||
|
||||
Reference in New Issue
Block a user