FINERACT-2385: Zero amount reage transaction should not be allowed
This commit is contained in:
committed by
Adam Saghy
parent
54e85c748d
commit
4ae6fd5694
+34
@@ -18,12 +18,15 @@
|
|||||||
*/
|
*/
|
||||||
package org.apache.fineract.test.stepdef.loan;
|
package org.apache.fineract.test.stepdef.loan;
|
||||||
|
|
||||||
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
|
|
||||||
import io.cucumber.datatable.DataTable;
|
import io.cucumber.datatable.DataTable;
|
||||||
import io.cucumber.java.en.Then;
|
import io.cucumber.java.en.Then;
|
||||||
import io.cucumber.java.en.When;
|
import io.cucumber.java.en.When;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import okhttp3.ResponseBody;
|
||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||||
import org.apache.fineract.client.models.PostLoansResponse;
|
import org.apache.fineract.client.models.PostLoansResponse;
|
||||||
@@ -34,6 +37,7 @@ import org.apache.fineract.test.messaging.EventAssertion;
|
|||||||
import org.apache.fineract.test.messaging.event.loan.LoanReAgeEvent;
|
import org.apache.fineract.test.messaging.event.loan.LoanReAgeEvent;
|
||||||
import org.apache.fineract.test.stepdef.AbstractStepDef;
|
import org.apache.fineract.test.stepdef.AbstractStepDef;
|
||||||
import org.apache.fineract.test.support.TestContextKey;
|
import org.apache.fineract.test.support.TestContextKey;
|
||||||
|
import org.junit.jupiter.api.Assertions;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import retrofit2.Response;
|
import retrofit2.Response;
|
||||||
|
|
||||||
@@ -112,4 +116,34 @@ public class LoanReAgingStepDef extends AbstractStepDef {
|
|||||||
|
|
||||||
eventAssertion.assertEventRaised(LoanReAgeEvent.class, loanId);
|
eventAssertion.assertEventRaised(LoanReAgeEvent.class, loanId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@When("Admin fails to create a Loan re-aging transaction with error {string} and with the following data:")
|
||||||
|
public void adminFailsToCreateReAgingTransactionWithError(final String expectedError, final DataTable table) throws IOException {
|
||||||
|
final Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||||
|
final long loanId = loanResponse.body().getLoanId();
|
||||||
|
|
||||||
|
final List<String> data = table.asLists().get(1);
|
||||||
|
final int frequencyNumber = Integer.parseInt(data.get(0));
|
||||||
|
final String frequencyType = data.get(1);
|
||||||
|
final String startDate = data.get(2);
|
||||||
|
final int numberOfInstallments = Integer.parseInt(data.get(3));
|
||||||
|
|
||||||
|
final PostLoansLoanIdTransactionsRequest reAgingRequest = LoanRequestFactory//
|
||||||
|
.defaultReAgingRequest()//
|
||||||
|
.frequencyNumber(frequencyNumber)//
|
||||||
|
.frequencyType(frequencyType)//
|
||||||
|
.startDate(startDate)//
|
||||||
|
.numberOfInstallments(numberOfInstallments);//
|
||||||
|
|
||||||
|
final Response<PostLoansLoanIdTransactionsResponse> response = loanTransactionsApi
|
||||||
|
.executeLoanTransaction(loanId, reAgingRequest, "reAge").execute();
|
||||||
|
|
||||||
|
try (ResponseBody errorBody = response.errorBody()) {
|
||||||
|
Assertions.assertNotNull(errorBody);
|
||||||
|
assertThat(errorBody.string()).contains(expectedError);
|
||||||
|
}
|
||||||
|
|
||||||
|
ErrorHelper.checkFailedApiCall(response, 403);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3063,3 +3063,106 @@ Feature: LoanReAging
|
|||||||
| NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 |
|
| NSF fee | true | Specified due date | 01 October 2024 | Flat | 20.0 | 0.0 | 0.0 | 20.0 |
|
||||||
| NSF fee | true | Specified due date | 01 November 2024 | Flat | 30.0 | 0.0 | 0.0 | 30.0 |
|
| NSF fee | true | Specified due date | 01 November 2024 | Flat | 30.0 | 0.0 | 0.0 | 30.0 |
|
||||||
|
|
||||||
|
Scenario: Verify that Loan re-aging with zero outstanding balance is rejected in real-time
|
||||||
|
When Admin sets the business date to "01 January 2024"
|
||||||
|
When Admin creates a client with random data
|
||||||
|
When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||||
|
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_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION | 01 January 2024 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 45 | DAYS | 15 | DAYS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||||
|
And Admin successfully approves the loan on "01 January 2024" with "1000" amount and expected disbursement date on "01 January 2024"
|
||||||
|
When Admin successfully disburse the loan on "01 January 2024" with "1000" EUR transaction amount
|
||||||
|
Then Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
When Admin sets the business date to "20 February 2024"
|
||||||
|
And Customer makes "AUTOPAY" repayment on "20 February 2024" with 750 EUR transaction amount
|
||||||
|
Then Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | 20 February 2024 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | 20 February 2024 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | 20 February 2024 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
And Admin adds "LOAN_NSF_FEE" due date charge with "01 March 2024" due date and 10 EUR transaction amount
|
||||||
|
Then Loan Repayment schedule has 5 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | 20 February 2024 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | 20 February 2024 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | 20 February 2024 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 5 | 15 | 01 March 2024 | | 0.0 | 0.0 | 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 |
|
||||||
|
When Admin fails to create a Loan re-aging transaction with error "error.msg.loan.reage.no.outstanding.balance.to.reage" and with the following data:
|
||||||
|
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||||
|
| 1 | MONTHS | 01 March 2024 | 3 |
|
||||||
|
Then Loan Repayment schedule has 5 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | 20 February 2024 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | 20 February 2024 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | 20 February 2024 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 5 | 15 | 01 March 2024 | | 0.0 | 0.0 | 0.0 | 0.0 | 10.0 | 10.0 | 0.0 | 0.0 | 0.0 | 10.0 |
|
||||||
|
Then Loan Transactions tab has the following data:
|
||||||
|
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||||
|
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false |
|
||||||
|
| 01 January 2024 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false |
|
||||||
|
| 20 February 2024 | Repayment | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false |
|
||||||
|
Then Loan Charges tab has the following data:
|
||||||
|
| Name | isPenalty | Payment due at | Due as of | Calculation type | Due | Paid | Waived | Outstanding |
|
||||||
|
| NSF fee | true | Specified due date | 01 March 2024 | Flat | 10.0 | 0.0 | 0.0 | 10.0 |
|
||||||
|
|
||||||
|
Scenario: Verify that zero amount reage transaction is reverted during reverse-replay
|
||||||
|
When Admin sets the business date to "01 January 2024"
|
||||||
|
When Admin creates a client with random data
|
||||||
|
When Admin set "LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION" loan product "DEFAULT" transaction type to "NEXT_INSTALLMENT" future installment allocation rule
|
||||||
|
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_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION | 01 January 2024 | 1000 | 0 | FLAT | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 45 | DAYS | 15 | DAYS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||||
|
And Admin successfully approves the loan on "01 January 2024" with "1000" amount and expected disbursement date on "01 January 2024"
|
||||||
|
When Admin successfully disburse the loan on "01 January 2024" with "1000" EUR transaction amount
|
||||||
|
Then Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
When Admin sets the business date to "20 February 2024"
|
||||||
|
When Admin creates a Loan re-aging transaction with the following data:
|
||||||
|
| frequencyNumber | frequencyType | startDate | numberOfInstallments |
|
||||||
|
| 1 | MONTHS | 01 March 2024 | 3 |
|
||||||
|
Then Loan Repayment schedule has 7 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | 20 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | 20 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | 20 February 2024 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 5 | 15 | 01 March 2024 | | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 6 | 31 | 01 April 2024 | | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
| 7 | 30 | 01 May 2024 | | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 |
|
||||||
|
Then Loan Transactions tab has the following data:
|
||||||
|
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||||
|
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false |
|
||||||
|
| 01 January 2024 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false |
|
||||||
|
| 20 February 2024 | Re-age | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false |
|
||||||
|
When Admin sets the business date to "21 February 2024"
|
||||||
|
And Customer makes "AUTOPAY" repayment on "19 February 2024" with 750 EUR transaction amount
|
||||||
|
Then Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||||
|
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||||
|
| | | 01 January 2024 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||||
|
| 1 | 0 | 01 January 2024 | 01 January 2024 | 750.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 |
|
||||||
|
| 2 | 15 | 16 January 2024 | 19 February 2024 | 500.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 3 | 15 | 31 January 2024 | 19 February 2024 | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
| 4 | 15 | 15 February 2024 | 19 February 2024 | 0.0 | 250.0 | 0.0 | 0.0 | 0.0 | 250.0 | 250.0 | 0.0 | 250.0 | 0.0 |
|
||||||
|
Then Loan Transactions tab has the following data:
|
||||||
|
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted |
|
||||||
|
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false |
|
||||||
|
| 01 January 2024 | Down Payment | 250.0 | 250.0 | 0.0 | 0.0 | 0.0 | 750.0 | false |
|
||||||
|
| 19 February 2024 | Repayment | 750.0 | 750.0 | 0.0 | 0.0 | 0.0 | 0.0 | false |
|
||||||
|
|||||||
+5
@@ -2902,6 +2902,11 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
|||||||
loanTransaction.updateComponentsAndTotal(outstandingPrincipalBalance.get(), Money.zero(currency), Money.zero(currency),
|
loanTransaction.updateComponentsAndTotal(outstandingPrincipalBalance.get(), Money.zero(currency), Money.zero(currency),
|
||||||
Money.zero(currency));
|
Money.zero(currency));
|
||||||
|
|
||||||
|
if (outstandingPrincipalBalance.get().isZero()) {
|
||||||
|
loanTransaction.reverse();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
Money calculatedPrincipal = Money.zero(currency);
|
Money calculatedPrincipal = Money.zero(currency);
|
||||||
Money adjustCalculatedPrincipal = Money.zero(currency);
|
Money adjustCalculatedPrincipal = Money.zero(currency);
|
||||||
if (outstandingPrincipalBalance.get().isGreaterThanZero()) {
|
if (outstandingPrincipalBalance.get().isGreaterThanZero()) {
|
||||||
|
|||||||
+17
@@ -56,6 +56,7 @@ public class LoanReAgingValidator {
|
|||||||
public void validateReAge(Loan loan, JsonCommand command) {
|
public void validateReAge(Loan loan, JsonCommand command) {
|
||||||
validateReAgeRequest(loan, command);
|
validateReAgeRequest(loan, command);
|
||||||
validateReAgeBusinessRules(loan);
|
validateReAgeBusinessRules(loan);
|
||||||
|
validateReAgeOutstandingBalance(loan, command);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateReAgeRequest(Loan loan, JsonCommand command) {
|
private void validateReAgeRequest(Loan loan, JsonCommand command) {
|
||||||
@@ -180,4 +181,20 @@ public class LoanReAgingValidator {
|
|||||||
private boolean transactionHappenedAfterOther(LoanTransaction transaction, LoanTransaction otherTransaction) {
|
private boolean transactionHappenedAfterOther(LoanTransaction transaction, LoanTransaction otherTransaction) {
|
||||||
return new ChangeOperation(transaction).compareTo(new ChangeOperation(otherTransaction)) > 0;
|
return new ChangeOperation(transaction).compareTo(new ChangeOperation(otherTransaction)) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateReAgeOutstandingBalance(final Loan loan, final JsonCommand command) {
|
||||||
|
final LocalDate businessDate = getBusinessLocalDate();
|
||||||
|
final LocalDate startDate = command.dateValueOfParameterNamed(LoanReAgingApiConstants.startDate);
|
||||||
|
|
||||||
|
final boolean isBackdated = businessDate.isAfter(startDate);
|
||||||
|
if (isBackdated) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (loan.getSummary().getTotalPrincipalOutstanding().compareTo(java.math.BigDecimal.ZERO) == 0) {
|
||||||
|
throw new GeneralPlatformDomainRuleException("error.msg.loan.reage.no.outstanding.balance.to.reage",
|
||||||
|
"Loan cannot be re-aged as there are no outstanding balances to be re-aged", loan.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
+4
@@ -44,6 +44,7 @@ import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
|||||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
|
||||||
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanSummary;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||||
@@ -516,6 +517,9 @@ class LoanReAgingValidatorTest {
|
|||||||
given(loanProductRelatedDetail.getLoanScheduleType()).willReturn(LoanScheduleType.PROGRESSIVE);
|
given(loanProductRelatedDetail.getLoanScheduleType()).willReturn(LoanScheduleType.PROGRESSIVE);
|
||||||
given(loan.isInterestBearing()).willReturn(false);
|
given(loan.isInterestBearing()).willReturn(false);
|
||||||
given(loan.getLoanTransactions()).willReturn(List.of());
|
given(loan.getLoanTransactions()).willReturn(List.of());
|
||||||
|
LoanSummary loanSummary = mock(LoanSummary.class);
|
||||||
|
given(loan.getSummary()).willReturn(loanSummary);
|
||||||
|
given(loanSummary.getTotalPrincipalOutstanding()).willReturn(java.math.BigDecimal.valueOf(1000));
|
||||||
return loan;
|
return loan;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+14
-14
@@ -537,15 +537,15 @@ public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
long loanId = createdLoanId.get();
|
long loanId = createdLoanId.get();
|
||||||
PostLoansLoanIdTransactionsResponse repaymentResponse = loanTransactionHelper.makeLoanRepayment(loanId,
|
PostLoansLoanIdTransactionsResponse repaymentResponse = loanTransactionHelper.makeLoanRepayment(loanId,
|
||||||
new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("02 February 2023").locale("en")
|
new PostLoansLoanIdTransactionsRequest().dateFormat(DATETIME_PATTERN).transactionDate("02 February 2023").locale("en")
|
||||||
.transactionAmount(250.0));
|
.transactionAmount(200.0));
|
||||||
|
|
||||||
// verify transactions
|
// verify transactions
|
||||||
verifyTransactions(loanId, //
|
verifyTransactions(loanId, //
|
||||||
transaction(500.0, "Disbursement", "01 January 2023"), //
|
transaction(500.0, "Disbursement", "01 January 2023"), //
|
||||||
transaction(125.0, "Down Payment", "01 January 2023"), //
|
transaction(125.0, "Down Payment", "01 January 2023"), //
|
||||||
transaction(125.0, "Repayment", "01 February 2023"), //
|
transaction(125.0, "Repayment", "01 February 2023"), //
|
||||||
transaction(250.0, "Repayment", "02 February 2023"), //
|
transaction(200.0, "Repayment", "02 February 2023"), //
|
||||||
transaction(0.0, "Re-age", "27 February 2023") //
|
transaction(50.0, "Re-age", "27 February 2023") //
|
||||||
);
|
);
|
||||||
|
|
||||||
verifyRepaymentSchedule(loanId, //
|
verifyRepaymentSchedule(loanId, //
|
||||||
@@ -553,17 +553,17 @@ public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
installment(125.0, true, "01 January 2023"), //
|
installment(125.0, true, "01 January 2023"), //
|
||||||
installment(125.0, true, "16 January 2023"), //
|
installment(125.0, true, "16 January 2023"), //
|
||||||
installment(125.0, true, "31 January 2023"), //
|
installment(125.0, true, "31 January 2023"), //
|
||||||
installment(125.0, true, "15 February 2023"), //
|
installment(75.00, true, "15 February 2023"), //
|
||||||
installment(0.0, true, "01 March 2023"), //
|
installment(8.33, false, "01 March 2023"), //
|
||||||
installment(0.0, true, "01 April 2023"), //
|
installment(8.33, false, "01 April 2023"), //
|
||||||
installment(0.0, true, "01 May 2023"), //
|
installment(8.33, false, "01 May 2023"), //
|
||||||
installment(0.0, true, "01 June 2023"), //
|
installment(8.33, false, "01 June 2023"), //
|
||||||
installment(0.0, true, "01 July 2023"), //
|
installment(8.33, false, "01 July 2023"), //
|
||||||
installment(0.0, true, "01 August 2023") //
|
installment(8.35, false, "01 August 2023") //
|
||||||
);
|
);
|
||||||
checkMaturityDates(loanId, LocalDate.of(2023, 8, 1), LocalDate.of(2023, 2, 2));
|
checkMaturityDates(loanId, LocalDate.of(2023, 8, 1), LocalDate.of(2023, 8, 1));
|
||||||
|
|
||||||
verifyLoanStatus(loanId, LoanStatus.CLOSED_OBLIGATIONS_MET);
|
verifyLoanStatus(loanId, LoanStatus.ACTIVE);
|
||||||
|
|
||||||
loanTransactionHelper.reverseLoanTransaction(loanId, repaymentResponse.getResourceId(),
|
loanTransactionHelper.reverseLoanTransaction(loanId, repaymentResponse.getResourceId(),
|
||||||
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("28 February 2023")
|
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("28 February 2023")
|
||||||
@@ -574,7 +574,7 @@ public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
transaction(500.0, "Disbursement", "01 January 2023"), //
|
transaction(500.0, "Disbursement", "01 January 2023"), //
|
||||||
transaction(125.0, "Down Payment", "01 January 2023"), //
|
transaction(125.0, "Down Payment", "01 January 2023"), //
|
||||||
transaction(125.0, "Repayment", "01 February 2023"), //
|
transaction(125.0, "Repayment", "01 February 2023"), //
|
||||||
reversedTransaction(250.0, "Repayment", "02 February 2023"), //
|
reversedTransaction(200.0, "Repayment", "02 February 2023"), //
|
||||||
transaction(250.0, "Re-age", "27 February 2023") //
|
transaction(250.0, "Re-age", "27 February 2023") //
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -607,7 +607,7 @@ public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
transaction(500.0, "Disbursement", "01 January 2023"), //
|
transaction(500.0, "Disbursement", "01 January 2023"), //
|
||||||
transaction(125.0, "Down Payment", "01 January 2023"), //
|
transaction(125.0, "Down Payment", "01 January 2023"), //
|
||||||
transaction(125.0, "Repayment", "01 February 2023"), //
|
transaction(125.0, "Repayment", "01 February 2023"), //
|
||||||
reversedTransaction(250.0, "Repayment", "02 February 2023"), //
|
reversedTransaction(200.0, "Repayment", "02 February 2023"), //
|
||||||
reversedTransaction(250.0, "Re-age", "27 February 2023") //
|
reversedTransaction(250.0, "Re-age", "27 February 2023") //
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user