FINERACT-1981: Fix progressive loan undo previous repayment
This commit is contained in:
committed by
Arnold Gálovics
parent
c71a39bb18
commit
4462127295
@@ -3377,3 +3377,21 @@ Feature: LoanRepayment
|
||||
| | | 23 July 2024 | | 111.92 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 23 August 2024 | 23 August 2024 | 0.0 | 111.92 | 0.0 | 0.0 | 5.0 | 116.92 | 116.92 | 114.72 | 0.0 | 0.0 |
|
||||
| 2 | 2 | 25 August 2024 | 23 August 2024 | 0.0 | 0.0 | 0.0 | 0.0 | 7.8 | 7.8 | 7.8 | 7.8 | 0.0 | 0.0 |
|
||||
|
||||
@AdvancedPaymentAllocation @ProgressiveLoanSchedule
|
||||
Scenario: Progressive loan, undo earlier repayment
|
||||
Given Global configuration "enable-business-date" is enabled
|
||||
When Admin sets the business date to "23 June 2024"
|
||||
When Admin creates a client with random data
|
||||
When Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_TILL_PRECLOSE | 23 June 2024 | 400 | 7.0 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "23 June 2024" with "400" amount and expected disbursement date on "23 June 2024"
|
||||
When Admin successfully disburse the loan on "23 June 2024" with "400" EUR transaction amount
|
||||
When Admin sets the business date to "24 June 2024"
|
||||
And Customer makes "AUTOPAY" repayment on "24 June 2024" with 100 EUR transaction amount
|
||||
When Admin sets the business date to "10 September 2024"
|
||||
And Customer makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "10 September 2024" with 400 EUR transaction amount and self-generated Idempotency key
|
||||
When Admin makes Credit Balance Refund transaction on "10 September 2024" with 91.21 EUR transaction amount
|
||||
When Customer undo "1"th "Repayment" transaction made on "24 June 2024"
|
||||
Then Loan status will be "ACTIVE"
|
||||
|
||||
@@ -2665,12 +2665,6 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom<Long> {
|
||||
final LoanLifecycleStateMachine loanLifecycleStateMachine, final LoanTransaction transactionForAdjustment,
|
||||
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds,
|
||||
final ScheduleGeneratorDTO scheduleGeneratorDTO, final ExternalId reversalExternalId) {
|
||||
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
||||
validateActivityNotBeforeLastTransactionDate(LoanEvent.LOAN_REPAYMENT_OR_WAIVER, transactionForAdjustment.getTransactionDate());
|
||||
validateRepaymentDateIsOnHoliday(newTransactionDetail.getTransactionDate(), holidayDetailDTO.isAllowTransactionsOnHoliday(),
|
||||
holidayDetailDTO.getHolidays());
|
||||
validateRepaymentDateIsOnNonWorkingDay(newTransactionDetail.getTransactionDate(), holidayDetailDTO.getWorkingDays(),
|
||||
holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
|
||||
|
||||
ChangedTransactionDetail changedTransactionDetail = null;
|
||||
|
||||
|
||||
+25
-5
@@ -72,6 +72,7 @@ import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
@@ -776,15 +777,34 @@ public final class LoanTransactionValidator {
|
||||
}
|
||||
}
|
||||
|
||||
public void validateActivityNotBeforeLastTransactionDate(final Loan loan, final LocalDate activityDate) {
|
||||
public void validateActivityNotBeforeLastTransactionDate(final Loan loan, final LocalDate activityDate, final LoanEvent event) {
|
||||
if (!(loan.repaymentScheduleDetail().isInterestRecalculationEnabled() || loan.loanProduct().isHoldGuaranteeFunds())) {
|
||||
return;
|
||||
}
|
||||
LocalDate lastTransactionDate = loan.getLastUserTransactionDate();
|
||||
if (DateUtils.isAfter(lastTransactionDate, activityDate)) {
|
||||
String errorMessage = "The date on which a repayment or waiver is made cannot be earlier than last transaction date";
|
||||
String action = "repayment.or.waiver";
|
||||
String postfix = "cannot.be.made.before.last.transaction.date";
|
||||
String errorMessage = null;
|
||||
String action = null;
|
||||
String postfix = null;
|
||||
switch (event) {
|
||||
case LOAN_REPAYMENT_OR_WAIVER -> {
|
||||
errorMessage = "The date on which a repayment or waiver is made cannot be earlier than last transaction date";
|
||||
action = "repayment.or.waiver";
|
||||
postfix = "cannot.be.made.before.last.transaction.date";
|
||||
}
|
||||
case WRITE_OFF_OUTSTANDING -> {
|
||||
errorMessage = "The date on which a write off is made cannot be earlier than last transaction date";
|
||||
action = "writeoff";
|
||||
postfix = "cannot.be.made.before.last.transaction.date";
|
||||
}
|
||||
case LOAN_CHARGE_PAYMENT -> {
|
||||
errorMessage = "The date on which a charge payment is made cannot be earlier than last transaction date";
|
||||
action = "charge.payment";
|
||||
postfix = "cannot.be.made.before.last.transaction.date";
|
||||
}
|
||||
default -> {
|
||||
}
|
||||
}
|
||||
throw new InvalidLoanStateTransitionException(action, postfix, errorMessage, lastTransactionDate);
|
||||
}
|
||||
}
|
||||
@@ -831,7 +851,7 @@ public final class LoanTransactionValidator {
|
||||
validateLoanHasNoLaterChargeRefundTransactionToReverseOrCreateATransaction(loan, transactionDate, "created");
|
||||
|
||||
validateClientOfficeJoiningDateIsBeforeTransactionDate(loan, transactionDate);
|
||||
validateActivityNotBeforeLastTransactionDate(loan, transactionDate);
|
||||
validateActivityNotBeforeLastTransactionDate(loan, transactionDate, LoanEvent.LOAN_REPAYMENT_OR_WAIVER);
|
||||
HolidayDetailDTO holidayDetailDTO = loanUtilService.constructHolidayDTO(loan.getOfficeId(), loan.getDisbursementDate());
|
||||
validateRepaymentDateIsOnHoliday(transactionDate, holidayDetailDTO.isAllowTransactionsOnHoliday(), holidayDetailDTO.getHolidays());
|
||||
validateRepaymentDateIsOnNonWorkingDay(transactionDate, holidayDetailDTO.getWorkingDays(),
|
||||
|
||||
+13
@@ -191,6 +191,7 @@ import org.apache.fineract.portfolio.loanaccount.exception.MultiDisbursementData
|
||||
import org.apache.fineract.portfolio.loanaccount.guarantor.service.GuarantorDomainService;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModel;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleModelPeriod;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.domain.LoanScheduleType;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.service.LoanScheduleHistoryWritePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.rescheduleloan.domain.LoanRescheduleRequest;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanApplicationValidator;
|
||||
@@ -1565,6 +1566,18 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
|
||||
|
||||
ScheduleGeneratorDTO scheduleGeneratorDTO = this.loanUtilService.buildScheduleGeneratorDTO(loan, recalculateFrom);
|
||||
|
||||
HolidayDetailDTO holidayDetailDTO = scheduleGeneratorDTO.getHolidayDetailDTO();
|
||||
if (loan.getLoanRepaymentScheduleDetail().getLoanScheduleType().equals(LoanScheduleType.CUMULATIVE)) {
|
||||
// validate cumulative
|
||||
loanTransactionValidator.validateActivityNotBeforeLastTransactionDate(loan, transactionToAdjust.getTransactionDate(),
|
||||
LoanEvent.LOAN_REPAYMENT_OR_WAIVER);
|
||||
}
|
||||
// common validations
|
||||
loanTransactionValidator.validateRepaymentDateIsOnHoliday(newTransactionDetail.getTransactionDate(),
|
||||
holidayDetailDTO.isAllowTransactionsOnHoliday(), holidayDetailDTO.getHolidays());
|
||||
loanTransactionValidator.validateRepaymentDateIsOnNonWorkingDay(newTransactionDetail.getTransactionDate(),
|
||||
holidayDetailDTO.getWorkingDays(), holidayDetailDTO.isAllowTransactionsOnNonWorkingDay());
|
||||
|
||||
final ChangedTransactionDetail changedTransactionDetail = loan.adjustExistingTransaction(newTransactionDetail,
|
||||
loanLifecycleStateMachine, transactionToAdjust, existingTransactionIds, existingReversedTransactionIds,
|
||||
scheduleGeneratorDTO, reversalTxnExternalId);
|
||||
|
||||
Reference in New Issue
Block a user