FINERACT-2326: Reprocessing loan internal api for testing purpose
This commit is contained in:
committed by
Aleksandar Vidakovic
parent
23080c5041
commit
000ebb4c1d
@@ -82,6 +82,7 @@ import org.apache.fineract.client.services.ImagesApi;
|
||||
import org.apache.fineract.client.services.InlineJobApi;
|
||||
import org.apache.fineract.client.services.InterestRateChartApi;
|
||||
import org.apache.fineract.client.services.InterestRateSlabAKAInterestBandsApi;
|
||||
import org.apache.fineract.client.services.InternalCobApi;
|
||||
import org.apache.fineract.client.services.JournalEntriesApi;
|
||||
import org.apache.fineract.client.services.ListReportMailingJobHistoryApi;
|
||||
import org.apache.fineract.client.services.LoanAccountLockApi;
|
||||
@@ -225,6 +226,7 @@ public final class FineractClient {
|
||||
public final HolidaysApi holidays;
|
||||
public final HooksApi hooks;
|
||||
public final ImagesApi images;
|
||||
public final InternalCobApi internalCob;
|
||||
public final InterestRateChartApi interestRateCharts;
|
||||
public final InterestRateSlabAKAInterestBandsApi interestRateChartLabs;
|
||||
public final JournalEntriesApi journalEntries;
|
||||
@@ -356,6 +358,7 @@ public final class FineractClient {
|
||||
holidays = retrofit.create(HolidaysApi.class);
|
||||
hooks = retrofit.create(HooksApi.class);
|
||||
images = retrofit.create(ImagesApi.class);
|
||||
internalCob = retrofit.create(InternalCobApi.class);
|
||||
interestRateCharts = retrofit.create(InterestRateChartApi.class);
|
||||
interestRateChartLabs = retrofit.create(InterestRateSlabAKAInterestBandsApi.class);
|
||||
journalEntries = retrofit.create(JournalEntriesApi.class);
|
||||
|
||||
+6
@@ -37,6 +37,7 @@ import org.apache.fineract.client.services.FundsApi;
|
||||
import org.apache.fineract.client.services.GeneralLedgerAccountApi;
|
||||
import org.apache.fineract.client.services.GlobalConfigurationApi;
|
||||
import org.apache.fineract.client.services.InlineJobApi;
|
||||
import org.apache.fineract.client.services.InternalCobApi;
|
||||
import org.apache.fineract.client.services.JournalEntriesApi;
|
||||
import org.apache.fineract.client.services.LoanAccountLockApi;
|
||||
import org.apache.fineract.client.services.LoanBuyDownFeesApi;
|
||||
@@ -268,4 +269,9 @@ public class ApiConfiguration {
|
||||
public LoanCapitalizedIncomeApi loanCapitalizedIncomeApi() {
|
||||
return fineractClient.createService(LoanCapitalizedIncomeApi.class);
|
||||
}
|
||||
|
||||
@Bean
|
||||
public InternalCobApi internalCobApi() {
|
||||
return fineractClient.createService(InternalCobApi.class);
|
||||
}
|
||||
}
|
||||
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
package org.apache.fineract.test.stepdef.loan;
|
||||
|
||||
import io.cucumber.java.en.When;
|
||||
import java.io.IOException;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
import org.apache.fineract.client.services.InternalCobApi;
|
||||
import org.apache.fineract.test.stepdef.AbstractStepDef;
|
||||
import org.apache.fineract.test.support.TestContextKey;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import retrofit2.Response;
|
||||
|
||||
public class LoanReprocessStepDef extends AbstractStepDef {
|
||||
|
||||
@Autowired
|
||||
private InternalCobApi internalCobApi;
|
||||
|
||||
@When("Admin runs loan reprocess for Loan")
|
||||
public void admin_runs_inline_COB_job_for_loan() throws IOException {
|
||||
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
|
||||
long loanId = loanResponse.body().getLoanId();
|
||||
|
||||
internalCobApi.loanReprocess(loanId).execute();
|
||||
}
|
||||
}
|
||||
@@ -7780,4 +7780,178 @@ Feature: LoanAccrualActivity
|
||||
When Loan Pay-off is made on "24 June 2025"
|
||||
Then Loan's all installments have obligations met
|
||||
|
||||
@TestRailId:C4052
|
||||
Scenario: Verify that no extra accrual activity will be created upon loan reprocessing with merchant issued refund and NSF fee
|
||||
When Admin sets the business date to "13 June 2025"
|
||||
And Admin creates a client with random data
|
||||
And 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_REFUND_INTEREST_RECALC_ACCRUAL_ACTIVITY | 13 June 2025 | 135.94 | 11.32 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "13 June 2025" with "135.94" amount and expected disbursement date on "13 June 2025"
|
||||
And Admin successfully disburse the loan on "13 June 2025" with "135.94" EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | | 113.81 | 22.13 | 1.28 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 2 | 31 | 13 August 2025 | | 91.47 | 22.34 | 1.07 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 3 | 31 | 13 September 2025 | | 68.92 | 22.55 | 0.86 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 4 | 30 | 13 October 2025 | | 46.16 | 22.76 | 0.65 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 5 | 31 | 13 November 2025 | | 23.19 | 22.97 | 0.44 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 6 | 30 | 13 December 2025 | | 0.0 | 23.19 | 0.22 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 4.52 | 0.0 | 0.0 | 140.46 | 0.0 | 0.0 | 0.0 | 140.46 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
# --- First repayment on 22 June 2025 ---
|
||||
When Admin sets the business date to "22 June 2025"
|
||||
And Admin makes "REPAYMENT" transaction with "AUTOPAY" payment type on "22 June 2025" with 25.00 EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | | 91.29 | 21.62 | 1.79 | 0.0 | 0.0 | 23.41 | 1.59 | 1.59 | 0.0 | 21.82 |
|
||||
| 3 | 31 | 13 September 2025 | | 68.74 | 22.55 | 0.86 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 4 | 30 | 13 October 2025 | | 45.98 | 22.76 | 0.65 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 5 | 31 | 13 November 2025 | | 23.0 | 22.98 | 0.43 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 6 | 30 | 13 December 2025 | | 0.0 | 23.0 | 0.22 | 0.0 | 0.0 | 23.22 | 0.0 | 0.0 | 0.0 | 23.22 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 4.33 | 0.0 | 0.0 | 140.27 | 25.0 | 25.0 | 0.0 | 115.27 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
# --- Second repayment on 13 July 2025 ---
|
||||
When Admin sets the business date to "13 July 2025"
|
||||
And Admin makes "REPAYMENT" transaction with "AUTOPAY" payment type on "13 July 2025" with 23.41 EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | 13 July 2025 | 90.24 | 22.67 | 0.74 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 13 September 2025 | | 68.51 | 21.73 | 1.68 | 0.0 | 0.0 | 23.41 | 1.59 | 1.59 | 0.0 | 21.82 |
|
||||
| 4 | 30 | 13 October 2025 | | 45.75 | 22.76 | 0.65 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 5 | 31 | 13 November 2025 | | 22.77 | 22.98 | 0.43 | 0.0 | 0.0 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 |
|
||||
| 6 | 30 | 13 December 2025 | | 0.0 |22.77 | 0.21 | 0.0 | 0.0 | 22.98 | 0.0 | 0.0 | 0.0 | 22.98 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 4.09 | 0.0 | 0.0 | 140.03 | 48.41 | 48.41 | 0.0 | 91.62 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
| 13 July 2025 | Repayment | 23.41 | 22.67 | 0.74 | 0.0 | 0.0 | 88.65 | false | false |
|
||||
# --- Merchant issued refund ---
|
||||
When Admin sets the business date to "16 July 2025"
|
||||
And Admin makes "MERCHANT_ISSUED_REFUND" transaction with "AUTOPAY" payment type on "16 July 2025" with 135.94 EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | 13 July 2025 | 90.24 | 22.67 | 0.74 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 13 September 2025 | 16 July 2025 | 66.91 | 23.33 | 0.08 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 13 October 2025 | 16 July 2025 | 43.5 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 5 | 31 | 13 November 2025 | 16 July 2025 | 20.09 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 6 | 30 | 13 December 2025 | 16 July 2025 | 0.0 | 20.09 | 0.0 | 0.0 | 0.0 | 20.09 | 20.09 | 20.09 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 1.2 | 0.0 | 0.0 | 137.14 | 137.14 | 137.14 | 0.0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
| 13 July 2025 | Repayment | 23.41 | 22.67 | 0.74 | 0.0 | 0.0 | 88.65 | false | false |
|
||||
| 13 July 2025 | Accrual Activity | 0.38 | 0.0 | 0.38 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Merchant Issued Refund | 135.94 | 88.65 | 0.08 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Interest Refund | 1.2 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Accrual | 1.2 | 0.0 | 1.2 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Accrual Activity | 0.82 | 0.0 | 0.82 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
And Loan status will be "OVERPAID"
|
||||
And Loan has 48.41 overpaid amount
|
||||
# --- Undo repayment made on 13 July 2025 on 18 July 2025 ---
|
||||
When Admin sets the business date to "18 July 2025"
|
||||
And Customer undo "1"th "Repayment" transaction made on "13 July 2025"
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | 16 July 2025 | 90.34 | 22.57 | 0.84 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 13 September 2025 | 16 July 2025 | 66.93 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 13 October 2025 | 16 July 2025 | 43.52 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 5 | 31 | 13 November 2025 | 16 July 2025 | 20.11 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 6 | 30 | 13 December 2025 | 16 July 2025 | 0.0 | 20.11 | 0.0 | 0.0 | 0.0 | 20.11 | 20.11 | 20.11 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 1.22 | 0.0 | 0.0 | 137.16 | 137.16 | 137.16 | 0.0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
| 13 July 2025 | Repayment | 23.41 | 22.67 | 0.74 | 0.0 | 0.0 | 88.65 | true | false |
|
||||
| 13 July 2025 | Accrual Activity | 0.38 | 0.0 | 0.38 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Accrual | 1.2 | 0.0 | 1.2 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Merchant Issued Refund | 135.94 | 111.32 | 0.84 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 16 July 2025 | Interest Refund | 1.22 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 16 July 2025 | Accrual Activity | 0.84 | 0.0 | 0.84 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 18 July 2025 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
And Loan status will be "OVERPAID"
|
||||
And Loan has 25 overpaid amount
|
||||
# --- Add NSF fee 18 on July 2025 ---
|
||||
When Admin adds "LOAN_NSF_FEE" due date charge with "18 July 2025" due date and 2.8 EUR transaction amount
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | 16 July 2025 | 90.34 | 22.57 | 0.84 | 0.0 | 2.8 | 26.21 | 26.21 | 26.21 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 13 September 2025 | 16 July 2025 | 66.93 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 13 October 2025 | 16 July 2025 | 43.52 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 5 | 31 | 13 November 2025 | 16 July 2025 | 20.11 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 6 | 30 | 13 December 2025 | 16 July 2025 | 0.0 | 20.11 | 0.0 | 0.0 | 0.0 | 20.11 | 20.11 | 20.11 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 1.22 | 0.0 | 2.8 | 139.96 | 139.96 | 139.96 | 0.0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
| 13 July 2025 | Repayment | 23.41 | 22.67 | 0.74 | 0.0 | 0.0 | 88.65 | true | false |
|
||||
| 13 July 2025 | Accrual Activity | 0.38 | 0.0 | 0.38 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Accrual | 1.2 | 0.0 | 1.2 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Merchant Issued Refund | 135.94 | 111.32 | 0.84 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
| 16 July 2025 | Interest Refund | 1.22 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 16 July 2025 | Accrual Activity | 3.64 | 0.0 | 0.84 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
| 18 July 2025 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 18 July 2025 | Accrual | 2.8 | 0.0 | 0.0 | 0.0 | 2.8 | 0.0 | false | false |
|
||||
And Loan status will be "OVERPAID"
|
||||
And Loan has 22.2 overpaid amount
|
||||
# --- Reprocess the loan on 18 July 2025 ---
|
||||
When Admin runs loan reprocess for Loan
|
||||
Then Loan Repayment schedule has 6 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 |
|
||||
| | | 13 June 2025 | | 135.94 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 30 | 13 July 2025 | 22 June 2025 | 112.91 | 23.03 | 0.38 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 2 | 31 | 13 August 2025 | 16 July 2025 | 90.34 | 22.57 | 0.84 | 0.0 | 2.8 | 26.21 | 26.21 | 26.21 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 13 September 2025 | 16 July 2025 | 66.93 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 13 October 2025 | 16 July 2025 | 43.52 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 5 | 31 | 13 November 2025 | 16 July 2025 | 20.11 | 23.41 | 0.0 | 0.0 | 0.0 | 23.41 | 23.41 | 23.41 | 0.0 | 0.0 |
|
||||
| 6 | 30 | 13 December 2025 | 16 July 2025 | 0.0 | 20.11 | 0.0 | 0.0 | 0.0 | 20.11 | 20.11 | 20.11 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 135.94 | 1.22 | 0.0 | 2.8 | 139.96 | 139.96 | 139.96 | 0.0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 13 June 2025 | Disbursement | 135.94 | 0.0 | 0.0 | 0.0 | 0.0 | 135.94 | false | false |
|
||||
| 22 June 2025 | Repayment | 25.0 | 24.62 | 0.38 | 0.0 | 0.0 | 111.32 | false | false |
|
||||
| 13 July 2025 | Repayment | 23.41 | 22.67 | 0.74 | 0.0 | 0.0 | 88.65 | true | false |
|
||||
| 13 July 2025 | Accrual Activity | 0.38 | 0.0 | 0.38 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Accrual | 1.2 | 0.0 | 1.2 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 July 2025 | Merchant Issued Refund | 135.94 | 111.32 | 0.84 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
| 16 July 2025 | Interest Refund | 1.22 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 16 July 2025 | Accrual Activity | 3.64 | 0.0 | 0.84 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
| 18 July 2025 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 18 July 2025 | Accrual | 2.8 | 0.0 | 0.0 | 0.0 | 2.8 | 0.0 | false | false |
|
||||
And Loan status will be "OVERPAID"
|
||||
And Loan has 22.2 overpaid amount
|
||||
|
||||
|
||||
+1
-1
@@ -26,7 +26,7 @@ Feature: MerchantIssuedRefund
|
||||
| 22 May 2025 | Repayment | 63.85 | 62.57 | 1.28 | 0.0 | 0.0 | 113.83 | true | false |
|
||||
| 22 May 2025 | Accrual Activity | 1.69 | 0.0 | 1.69 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 28 May 2025 | Accrual | 1.9 | 0.0 | 1.9 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 28 May 2025 | Interest Refund | 2.01 | 0.0 | 0.0 | 0.0 | 0.0 | 176.4 | false | true |
|
||||
| 28 May 2025 | Interest Refund | 2.01 | 0.0 | 0.0 | 0.0 | 0.0 | 0.0 | false | true |
|
||||
| 28 May 2025 | Accrual | 0.11 | 0.0 | 0.11 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 28 May 2025 | Merchant Issued Refund | 187.99 | 176.4 | 1.6 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
| 28 May 2025 | Accrual Activity | 3.12 | 0.0 | 0.32 | 0.0 | 2.8 | 0.0 | false | true |
|
||||
|
||||
+3
@@ -319,6 +319,9 @@ public class LoanTransaction extends AbstractAuditableWithUTCDateTimeCustom<Long
|
||||
newTransaction.setLoanReAgeParameter(loanTransaction.getLoanReAgeParameter().getCopy(newTransaction));
|
||||
}
|
||||
newTransaction.setClassification(loanTransaction.getClassification());
|
||||
if (loanTransaction.isAccrualActivity()) {
|
||||
newTransaction.setCreatedBy(loanTransaction.getCreatedBy().get());
|
||||
}
|
||||
return newTransaction;
|
||||
}
|
||||
|
||||
|
||||
+11
@@ -325,6 +325,17 @@ public interface LoanTransactionRepository extends JpaRepository<LoanTransaction
|
||||
List<LoanTransaction> findNonReversedLoanAndTypeAndDates(@Param("loan") Loan loan, @Param("type") LoanTransactionType type,
|
||||
@Param("transactionDates") Set<LocalDate> transactionDates);
|
||||
|
||||
@Query("""
|
||||
SELECT lt FROM LoanTransaction lt
|
||||
WHERE lt.loan = :loan
|
||||
AND lt.reversed = false
|
||||
AND lt.typeOf = :type
|
||||
AND lt.dateOf = :transactionDate
|
||||
ORDER BY lt.dateOf, lt.createdDate, lt.id
|
||||
""")
|
||||
List<LoanTransaction> findNonReversedLoanAndTypeAndDate(@Param("loan") Loan loan, @Param("type") LoanTransactionType type,
|
||||
@Param("transactionDate") LocalDate transactionDate);
|
||||
|
||||
@Query("""
|
||||
SELECT lt FROM LoanTransaction lt
|
||||
WHERE lt.loan = :loan
|
||||
|
||||
+17
-2
@@ -91,6 +91,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelation;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRelationTypeEnum;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.SingleLoanChargeRepaymentScheduleProcessingWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reaging.LoanReAgeParameter;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.AbstractLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
|
||||
@@ -129,6 +130,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
private final LoanScheduleComponent loanSchedule;
|
||||
private final LoanTransactionRepository loanTransactionRepository;
|
||||
private final LoanChargeService loanChargeService;
|
||||
private final SingleLoanChargeRepaymentScheduleProcessingWrapper loanChargeRepaymentScheduleProcessing;
|
||||
|
||||
public AdvancedPaymentScheduleTransactionProcessor(final EMICalculator emiCalculator, final LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
final InterestRefundService interestRefundService, final ExternalIdFactory externalIdFactory,
|
||||
@@ -142,6 +144,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
this.loanTransactionRepository = loanTransactionRepository;
|
||||
this.loanSchedule = loanSchedule;
|
||||
this.loanChargeService = loanChargeService;
|
||||
this.loanChargeRepaymentScheduleProcessing = new SingleLoanChargeRepaymentScheduleProcessingWrapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -233,6 +236,7 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
|
||||
List<ChangeOperation> changeOperations = createSortedChangeList(loanTermVariations, loanTransactions, charges);
|
||||
|
||||
List<Long> loanChargeIdProcessed = new ArrayList<>();
|
||||
List<LoanTransaction> overpaidTransactions = new ArrayList<>();
|
||||
for (final ChangeOperation changeOperation : changeOperations) {
|
||||
if (changeOperation.isLoanTermVariationsData()) {
|
||||
@@ -240,6 +244,16 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
processLoanTermVariation(installments, interestRateChange, scheduleModel);
|
||||
} else if (changeOperation.isTransaction()) {
|
||||
LoanTransaction transaction = changeOperation.getLoanTransaction().get();
|
||||
if (loan.getStatus().isOverpaid() && transaction.isAccrualActivity()) {
|
||||
for (LoanCharge loanCharge : ctx.getCharges()) {
|
||||
if (loanCharge.isDueDateCharge() && !loanChargeIdProcessed.contains(loanCharge.getId())
|
||||
&& !DateUtils.isAfter(loan.getClosedOnDate(), loanCharge.getDueLocalDate())) {
|
||||
loanChargeRepaymentScheduleProcessing.reprocess(transaction.getLoan().getCurrency(),
|
||||
transaction.getLoan().getDisbursementDate(), ctx.getInstallments(), loanCharge);
|
||||
loanChargeIdProcessed.add(loanCharge.getId());
|
||||
}
|
||||
}
|
||||
}
|
||||
processSingleTransaction(transaction, ctx);
|
||||
transaction = getProcessedTransaction(changedTransactionDetail, transaction);
|
||||
ctx.getAlreadyProcessedTransactions().add(transaction);
|
||||
@@ -248,7 +262,9 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
}
|
||||
} else {
|
||||
LoanCharge loanCharge = changeOperation.getLoanCharge().get();
|
||||
processSingleCharge(loanCharge, currency, installments, disbursementDate);
|
||||
if (!loanChargeIdProcessed.contains(loanCharge.getId())) {
|
||||
processSingleCharge(loanCharge, currency, installments, disbursementDate);
|
||||
}
|
||||
if (!loanCharge.isFullyPaid() && !overpaidTransactions.isEmpty()) {
|
||||
overpaidTransactions = processOverpaidTransactions(overpaidTransactions, ctx);
|
||||
}
|
||||
@@ -1137,7 +1153,6 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
remainingTransactions.remove(transaction);
|
||||
if (processTransaction.isOverPaid()) {
|
||||
remainingTransactions.add(processTransaction);
|
||||
break;
|
||||
}
|
||||
}
|
||||
return remainingTransactions;
|
||||
|
||||
+11
@@ -21,6 +21,7 @@ package org.apache.fineract.cob.api;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.ws.rs.Consumes;
|
||||
import jakarta.ws.rs.GET;
|
||||
import jakarta.ws.rs.POST;
|
||||
@@ -46,6 +47,7 @@ import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer
|
||||
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.context.annotation.Profile;
|
||||
import org.springframework.stereotype.Component;
|
||||
@@ -54,6 +56,7 @@ import org.springframework.stereotype.Component;
|
||||
@Component
|
||||
@Path("/v1/internal/cob")
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "Internal COB", description = "Internal COB api for testing purpose")
|
||||
@Slf4j
|
||||
public class InternalCOBApiResource implements InitializingBean {
|
||||
|
||||
@@ -63,6 +66,7 @@ public class InternalCOBApiResource implements InitializingBean {
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
private final ToApiJsonSerializer<List> toApiJsonSerializerForList;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
|
||||
protected DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(DATETIME_PATTERN);
|
||||
|
||||
@@ -103,4 +107,11 @@ public class InternalCOBApiResource implements InitializingBean {
|
||||
loanRepositoryWrapper.save(loan);
|
||||
}
|
||||
|
||||
@POST
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Path("loan-reprocess/{loanId}")
|
||||
public void loanReprocess(@Context final UriInfo uriInfo, @PathParam("loanId") long loanId) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loanRepositoryWrapper.findOneWithNotFoundDetection(loanId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-4
@@ -236,8 +236,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
.append("ln.interest_repaid_derived As interestPaid, ")
|
||||
.append("sum(COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_amount ELSE 0.0 END), 0.0) - COALESCE((CASE WHEN ln.loan_status_id = 300 THEN ls.fee_charges_completed_derived ELSE 0.0 END), 0.0)) As feeDue, ")
|
||||
.append("ln.fee_charges_repaid_derived As feePaid, ").append("ca.attendance_type_enum as attendanceTypeId ")
|
||||
.append("FROM m_group gp ")
|
||||
.append("LEFT JOIN m_office of ON of.id = gp.office_id AND of.hierarchy like :officeHierarchy ")
|
||||
.append("FROM m_group gp ").append("LEFT JOIN m_office o ON o.id = gp.office_id AND o.hierarchy like :officeHierarchy ")
|
||||
.append("JOIN m_group_level gl ON gl.id = gp.level_Id ").append("LEFT JOIN m_staff sf ON sf.id = gp.staff_id ")
|
||||
.append("JOIN m_group_client gc ON gc.group_id = gp.id ").append("JOIN m_client cl ON cl.id = gc.client_id ")
|
||||
.append("LEFT JOIN m_loan ln ON cl.id = ln.client_id and ln.group_id=gp.id AND ln.group_id is not null AND ( ln.loan_status_id = 300 ) ")
|
||||
@@ -511,8 +510,7 @@ public class CollectionSheetReadPlatformServiceImpl implements CollectionSheetRe
|
||||
.append("rc.internationalized_name_code as currencyNameCode, ")
|
||||
.append("SUM(COALESCE(mss.deposit_amount,0) - coalesce(mss.deposit_amount_completed_derived,0)) as dueAmount ")
|
||||
|
||||
.append("FROM m_group gp ")
|
||||
.append("LEFT JOIN m_office of ON of.id = gp.office_id AND of.hierarchy like :officeHierarchy ")
|
||||
.append("FROM m_group gp ").append("LEFT JOIN m_office o ON o.id = gp.office_id AND o.hierarchy like :officeHierarchy ")
|
||||
.append("JOIN m_group_level gl ON gl.id = gp.level_Id ").append("LEFT JOIN m_staff sf ON sf.id = gp.staff_id ")
|
||||
.append("JOIN m_group_client gc ON gc.group_id = gp.id ").append("JOIN m_client cl ON cl.id = gc.client_id ")
|
||||
.append("JOIN m_savings_account sa ON sa.client_id=cl.id and sa.status_enum=300 ")
|
||||
|
||||
+3
-3
@@ -188,7 +188,7 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
|
||||
+ " g.hierarchy as hierarchy, c.id as calendarId, ci.id as calendarInstanceId, ci.entity_id as entityId,"
|
||||
+ " ci.entity_type_enum as entityTypeId, c.title as title, c.description as description,"
|
||||
+ "c.location as location, c.start_date as startDate, c.end_date as endDate, c.recurrence as recurrence,c.meeting_time as meetingTime,"
|
||||
+ "sum(CASE WHEN l.loan_status_id=300 and lrs.duedate = ? THEN COALESCE(lrs.principal_amount,0)) + (COALESCE(lrs.interest_amount,0) ELSE 0 END)) as installmentDue,"
|
||||
+ "sum(CASE WHEN l.loan_status_id=300 and lrs.duedate = ? THEN COALESCE(lrs.principal_amount,0) + COALESCE(lrs.interest_amount,0) ELSE 0 END) as installmentDue,"
|
||||
+ "sum(CASE WHEN l.loan_status_id=300 and lrs.duedate = ? THEN COALESCE(lrs.principal_completed_derived,0) + COALESCE(lrs.interest_completed_derived,0) ELSE 0 END) as totalCollected,"
|
||||
+ "sum(CASE WHEN l.loan_status_id=300 and lrs.duedate <= ? THEN COALESCE(lrs.principal_amount,0) + COALESCE(lrs.interest_amount,0) ELSE 0 END)"
|
||||
+ "- sum(CASE WHEN l.loan_status_id=300 and lrs.duedate <= ? THEN COALESCE(lrs.principal_completed_derived,0) + COALESCE(lrs.interest_completed_derived,0) ELSE 0 END) as totaldue, "
|
||||
@@ -495,8 +495,8 @@ public class CenterReadPlatformServiceImpl implements CenterReadPlatformService
|
||||
String sql = centerCalendarMapper.schema();
|
||||
Collection<CenterData> centerDataArray;
|
||||
if (staffId != null) {
|
||||
sql += " and g.staff_id=? ";
|
||||
sql += "and lrs.duedate<=? and l.loan_type_enum=3";
|
||||
sql += " and g.staff_id = ? ";
|
||||
sql += " and lrs.duedate <= ? "; // and l.loan_type_enum = 3 ";
|
||||
sql += " group by c.id, ci.id, g.account_no, g.external_id, g.status_enum, g.activation_date, g.hierarchy";
|
||||
centerDataArray = this.jdbcTemplate.query(sql, centerCalendarMapper, // NOSONAR
|
||||
meetingDate, meetingDate, meetingDate, meetingDate, meetingDate, meetingDate, officeId, staffId, meetingDate);
|
||||
|
||||
-2
@@ -63,7 +63,6 @@ import org.apache.fineract.portfolio.loanaccount.repository.LoanBuyDownFeeBalanc
|
||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanTransactionValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.BuyDownFeePlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualsProcessingService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanBalanceService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanDownPaymentHandlerService;
|
||||
@@ -100,7 +99,6 @@ public class LoanAdjustmentServiceImpl implements LoanAdjustmentService {
|
||||
private final LoanBalanceService loanBalanceService;
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
||||
private final BuyDownFeePlatformService buyDownFeePlatformService;
|
||||
private final LoanBuyDownFeeBalanceRepository loanBuyDownFeeBalanceRepository;
|
||||
|
||||
@Override
|
||||
|
||||
+146
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests;
|
||||
|
||||
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.InterestRateFrequencyType.MONTHS;
|
||||
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.InterestRateFrequencyType.WHOLE_TERM;
|
||||
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.InterestRateFrequencyType.YEARS;
|
||||
import static org.apache.fineract.integrationtests.BaseLoanIntegrationTest.RepaymentFrequencyType.DAYS;
|
||||
@@ -41,6 +42,7 @@ import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
import org.apache.fineract.client.models.AdvancedPaymentData;
|
||||
import org.apache.fineract.client.models.BusinessDateUpdateRequest;
|
||||
import org.apache.fineract.client.models.CreditAllocationData;
|
||||
@@ -62,6 +64,7 @@ import org.apache.fineract.client.models.PostLoanProductsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsRequest;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse;
|
||||
import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionIdRequest;
|
||||
import org.apache.fineract.client.models.PostLoansRequest;
|
||||
import org.apache.fineract.client.models.PostLoansResponse;
|
||||
@@ -78,9 +81,11 @@ import org.apache.fineract.integrationtests.common.accounting.Account;
|
||||
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
|
||||
import org.apache.fineract.integrationtests.common.accounting.PeriodicAccrualAccountingHelper;
|
||||
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.CobHelper;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanProductTestBuilder;
|
||||
import org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper;
|
||||
import org.apache.fineract.integrationtests.common.organisation.StaffHelper;
|
||||
import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper;
|
||||
import org.apache.fineract.integrationtests.common.system.CodeHelper;
|
||||
import org.apache.fineract.integrationtests.useradministration.roles.RolesHelper;
|
||||
import org.apache.fineract.integrationtests.useradministration.users.UserHelper;
|
||||
@@ -6000,6 +6005,147 @@ public class AdvancedPaymentAllocationLoanRepaymentScheduleTest extends BaseLoan
|
||||
});
|
||||
}
|
||||
|
||||
// UC156: Loan Transaction reprocess
|
||||
@Test
|
||||
public void uc156() {
|
||||
final String operationDate = "13 June 2025";
|
||||
AtomicLong createdLoanId = new AtomicLong();
|
||||
AtomicLong secondRepayment = new AtomicLong();
|
||||
AtomicLong createdLoanChargeId = new AtomicLong();
|
||||
final BigDecimal interestRatePerPeriod = BigDecimal.valueOf(11.32);
|
||||
final BigDecimal principalAmount = BigDecimal.valueOf(135.94);
|
||||
final Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec, List.of(//
|
||||
Pair.of(1, 10), //
|
||||
Pair.of(11, 30), //
|
||||
Pair.of(31, 60), //
|
||||
Pair.of(61, null)//
|
||||
));
|
||||
|
||||
runAt(operationDate, () -> {
|
||||
final ArrayList<String> interestRefundTypes = new ArrayList<String>();
|
||||
interestRefundTypes.add("PAYOUT_REFUND");
|
||||
interestRefundTypes.add("MERCHANT_ISSUED_REFUND");
|
||||
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation()
|
||||
.interestRatePerPeriod(interestRatePerPeriod.doubleValue()).interestRateFrequencyType(YEARS)//
|
||||
.daysInMonthType(DaysInMonthType.DAYS_30)//
|
||||
.daysInYearType(DaysInYearType.DAYS_360)//
|
||||
.numberOfRepayments(6)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(2L)//
|
||||
.chargeOffBehaviour("ZERO_INTEREST")//
|
||||
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue())//
|
||||
.repaymentStartDateType(LoanProduct.RepaymentStartDateTypeEnum.SUBMITTED_ON_DATE.ordinal())//
|
||||
.enableDownPayment(false)//
|
||||
.enableAccrualActivityPosting(true)//
|
||||
.allowPartialPeriodInterestCalcualtion(null)//
|
||||
.enableAutoRepaymentForDownPayment(null)//
|
||||
.isInterestRecalculationEnabled(true)//
|
||||
.delinquencyBucketId(delinquencyBucketId.longValue())//
|
||||
.enableInstallmentLevelDelinquency(true)//
|
||||
.interestRecalculationCompoundingMethod(0)//
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodType.DAILY)//
|
||||
.installmentAmountInMultiplesOf(null)//
|
||||
.supportedInterestRefundTypes(interestRefundTypes) //
|
||||
.rescheduleStrategyMethod(LoanRescheduleStrategyMethod.ADJUST_LAST_UNPAID_PERIOD.getValue())//
|
||||
.recalculationRestFrequencyType(2)//
|
||||
.recalculationRestFrequencyInterval(1);
|
||||
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductResponse.getResourceId(), operationDate,
|
||||
principalAmount.doubleValue(), 6).interestCalculationPeriodType(DAYS)//
|
||||
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
|
||||
.interestRatePerPeriod(interestRatePerPeriod)//
|
||||
.repaymentEvery(1)//
|
||||
.repaymentFrequencyType(MONTHS)//
|
||||
.loanTermFrequency(6)//
|
||||
.loanTermFrequencyType(MONTHS);
|
||||
|
||||
PostLoansResponse loanResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||
createdLoanId.set(loanResponse.getLoanId());
|
||||
|
||||
loanTransactionHelper.approveLoan(loanResponse.getLoanId(), new PostLoansLoanIdRequest().approvedLoanAmount(principalAmount)
|
||||
.dateFormat(DATETIME_PATTERN).approvedOnDate(operationDate).locale("en"));
|
||||
|
||||
loanTransactionHelper.disburseLoan(loanResponse.getLoanId(), new PostLoansLoanIdRequest().actualDisbursementDate(operationDate)
|
||||
.dateFormat(DATETIME_PATTERN).locale("en").transactionAmount(principalAmount));
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(createdLoanId.get());
|
||||
assertTrue(loanDetails.getStatus().getActive());
|
||||
});
|
||||
|
||||
runAt("22 June 2025", () -> {
|
||||
PostLoansLoanIdTransactionsResponse repayment = loanTransactionHelper.makeLoanRepayment(createdLoanId.get(),
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("22 June 2025").dateFormat("dd MMMM yyyy").locale("en")
|
||||
.transactionAmount(25.0));
|
||||
});
|
||||
|
||||
runAt("13 July 2025", () -> {
|
||||
PostLoansLoanIdTransactionsResponse repayment = loanTransactionHelper.makeLoanRepayment(createdLoanId.get(),
|
||||
new PostLoansLoanIdTransactionsRequest().transactionDate("13 July 2025").dateFormat("dd MMMM yyyy").locale("en")
|
||||
.transactionAmount(23.41));
|
||||
secondRepayment.set(repayment.getResourceId());
|
||||
});
|
||||
|
||||
runAt("16 July 2025", () -> {
|
||||
loanTransactionHelper.makeMerchantIssuedRefund(createdLoanId.get(), new PostLoansLoanIdTransactionsRequest()
|
||||
.dateFormat(DATETIME_PATTERN).transactionDate("16 July 2025").locale("en").transactionAmount(135.94));
|
||||
});
|
||||
|
||||
runAt("18 July 2025", () -> {
|
||||
CobHelper.fastForwardLoansLastCOBDate(createdLoanId.get(), "18 July 2025");
|
||||
verifyLastClosedBusinessDate(createdLoanId.get(), "18 July 2025");
|
||||
loanTransactionHelper.reverseLoanTransaction(createdLoanId.get(), secondRepayment.get(),
|
||||
new PostLoansLoanIdTransactionsTransactionIdRequest().dateFormat(DATETIME_PATTERN).transactionDate("18 July 2025")
|
||||
.transactionAmount(0.0).locale("en"));
|
||||
|
||||
GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(createdLoanId.get());
|
||||
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||
verifyTransactions(createdLoanId.get(), //
|
||||
transaction(135.94, "Disbursement", "13 June 2025", 135.94, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(25.0, "Repayment", "22 June 2025", 111.32, 24.62, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(23.41, "Repayment", "13 July 2025", 88.65, 22.67, 0.74, 0.0, 0.0, 0.0, 0.0, true),
|
||||
transaction(0.38, "Accrual Activity", "13 July 2025", 0.0, 0.0, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(1.20, "Accrual", "16 July 2025", 0.0, 0.0, 1.20, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(135.94, "Merchant Issued Refund", "16 July 2025", 0.0, 111.32, 0.84, 0.0, 0.0, 0.0, 23.78),
|
||||
transaction(1.22, "Interest Refund", "16 July 2025", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.22),
|
||||
transaction(0.84, "Accrual Activity", "16 July 2025", 0.0, 0.0, 0.84, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(0.02, "Accrual", "18 July 2025", 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0));
|
||||
|
||||
createdLoanChargeId.set(addCharge(createdLoanId.get(), false, 2.8, "18 July 2025"));
|
||||
LOG.info("------------------------------ REPROCESSING LOAN ---------------------------------------");
|
||||
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(createdLoanId.get());
|
||||
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||
verifyTransactions(createdLoanId.get(), //
|
||||
transaction(135.94, "Disbursement", "13 June 2025", 135.94, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(25.0, "Repayment", "22 June 2025", 111.32, 24.62, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(23.41, "Repayment", "13 July 2025", 88.65, 22.67, 0.74, 0.0, 0.0, 0.0, 0.0, true),
|
||||
transaction(0.38, "Accrual Activity", "13 July 2025", 0.0, 0.0, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(1.20, "Accrual", "16 July 2025", 0.0, 0.0, 1.20, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(135.94, "Merchant Issued Refund", "16 July 2025", 0.0, 111.32, 0.84, 2.80, 0.0, 0.0, 20.98),
|
||||
transaction(1.22, "Interest Refund", "16 July 2025", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.22),
|
||||
transaction(3.64, "Accrual Activity", "16 July 2025", 0.0, 0.0, 0.84, 2.80, 0.0, 0.0, 0.0),
|
||||
transaction(0.02, "Accrual", "18 July 2025", 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(2.80, "Accrual", "18 July 2025", 0.0, 0.0, 0.00, 2.80, 0.0, 0.0, 0.0));
|
||||
|
||||
CobHelper.reprocessLoan(createdLoanId.get());
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(createdLoanId.get());
|
||||
assertTrue(loanDetails.getStatus().getOverpaid());
|
||||
|
||||
verifyTransactions(createdLoanId.get(), //
|
||||
transaction(135.94, "Disbursement", "13 June 2025", 135.94, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(25.0, "Repayment", "22 June 2025", 111.32, 24.62, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(23.41, "Repayment", "13 July 2025", 88.65, 22.67, 0.74, 0.0, 0.0, 0.0, 0.0, true),
|
||||
transaction(0.38, "Accrual Activity", "13 July 2025", 0.0, 0.0, 0.38, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(1.20, "Accrual", "16 July 2025", 0.0, 0.0, 1.20, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(135.94, "Merchant Issued Refund", "16 July 2025", 0.0, 111.32, 0.84, 2.80, 0.0, 0.0, 20.98),
|
||||
transaction(1.22, "Interest Refund", "16 July 2025", 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.22),
|
||||
transaction(3.64, "Accrual Activity", "16 July 2025", 0.0, 0.0, 0.84, 2.80, 0.0, 0.0, 0.0),
|
||||
transaction(0.02, "Accrual", "18 July 2025", 0.0, 0.0, 0.02, 0.0, 0.0, 0.0, 0.0),
|
||||
transaction(2.80, "Accrual", "18 July 2025", 0.0, 0.0, 0.0, 2.80, 0.0, 0.0, 0.0));
|
||||
});
|
||||
}
|
||||
|
||||
private Long applyAndApproveLoanProgressiveAdvancedPaymentAllocationStrategyMonthlyRepayments(Long clientId, Long loanProductId,
|
||||
Integer numberOfRepayments, String loanDisbursementDate, double amount) {
|
||||
LOG.info("------------------------------APPLY AND APPROVE LOAN ---------------------------------------");
|
||||
|
||||
+2
-2
@@ -992,7 +992,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
transaction(650.0, "Repayment", repaymentDate1, 0.0, 500.0, 0.0, 40.0, 30.0, 0.0, 80.0, false), //
|
||||
transaction(70.0, "Accrual", repaymentDate1, 0.0, 0.0, 0.0, 40.0, 30.0, 0.0, 0.0, false), //
|
||||
transaction(500.0, "Disbursement", disbursementDay2, 420.0, 0.0, 0.0, 0.0, 0.0, 0.0, 80.0, false), //
|
||||
transaction(70.0, "Accrual Activity", repaymentPeriod1DueDate, 0.0, 0.0, 0.0, 40.0, 30.0, 0.0, 0.0, false) //
|
||||
transaction(140.0, "Accrual Activity", repaymentPeriod1DueDate, 0.0, 0.0, 0.0, 80.0, 60.0, 0.0, 0.0, false) //
|
||||
);
|
||||
});
|
||||
}
|
||||
@@ -1044,7 +1044,7 @@ public class LoanTransactionAccrualActivityPostingTest extends BaseLoanIntegrati
|
||||
verifyTransactions(loanId.get(), transaction(650.0, "Repayment", repaymentDate1, 0.0, 500.0, 0.0, 40.0, 30.0, 0.0, 80.0, false), //
|
||||
transaction(500.0, "Disbursement", disbursementDay2, 420.0, 0.0, 0.0, 0.0, 0.0, 0.0, 80.0, false), //
|
||||
transaction(70.0, "Accrual", repaymentDate1, 0.0, 0.0, 0.0, 40.0, 30.0, 0.0, 0.0, false), //
|
||||
transaction(70.0, "Accrual Activity", repaymentPeriod1DueDate, 0.0, 0.0, 0.0, 40.0, 30.0, 0.0, 0.0, false), //
|
||||
transaction(140.0, "Accrual Activity", repaymentPeriod1DueDate, 0.0, 0.0, 0.0, 80.0, 60.0, 0.0, 0.0, false), //
|
||||
transaction(500.0, "Disbursement", disbursementDay, 500.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, false)); //
|
||||
|
||||
});
|
||||
|
||||
+2
-1
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.apache.fineract.integrationtests.common;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import okhttp3.logging.HttpLoggingInterceptor;
|
||||
@@ -43,7 +44,7 @@ public final class FineractClientHelper {
|
||||
String url = System.getProperty("fineract.it.url", buildURI());
|
||||
// insecure(true) should *ONLY* ever be used for https://localhost:8443, NOT in real clients!!
|
||||
FineractClient.Builder builder = FineractClient.builder().insecure(true).baseURL(url).tenant(ConfigProperties.Backend.TENANT)
|
||||
.basicAuth(username, password).logging(HttpLoggingInterceptor.Level.NONE);
|
||||
.basicAuth(username, password).logging(HttpLoggingInterceptor.Level.NONE).readTimeout(Duration.ofSeconds(0));
|
||||
customizer.accept(builder);
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
+9
-9
@@ -23,6 +23,8 @@ import io.restassured.specification.ResponseSpecification;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.fineract.client.util.Calls;
|
||||
import org.apache.fineract.integrationtests.common.FineractClientHelper;
|
||||
import org.apache.fineract.integrationtests.common.Utils;
|
||||
|
||||
@Slf4j
|
||||
@@ -41,15 +43,13 @@ public final class CobHelper {
|
||||
return Utils.performServerGet(requestSpec, responseSpec, url, jsonReturn);
|
||||
}
|
||||
|
||||
// TODO: Rewrite to use fineract-client instead!
|
||||
// Example: org.apache.fineract.integrationtests.common.loans.LoanTransactionHelper.disburseLoan(java.lang.Long,
|
||||
// org.apache.fineract.client.models.PostLoansLoanIdRequest)
|
||||
@Deprecated(forRemoval = true)
|
||||
public static void fastForwardLoansLastCOBDate(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final Integer loanId, final String cobDate) {
|
||||
final String url = "/fineract-provider/api/v1/internal/cob/fast-forward-cob-date-of-loan/" + loanId + "?" + Utils.TENANT_IDENTIFIER;
|
||||
log.info("-------------------- -----------FAST FORWARD LAST COB DATE OF LOAN ----------------------------------------");
|
||||
Utils.performServerPost(requestSpec, responseSpec, url, "{\"lastClosedBusinessDate\":\"" + cobDate + "\"}");
|
||||
public static void fastForwardLoansLastCOBDate(final Long loanId, final String cobDate) {
|
||||
Calls.ok(FineractClientHelper.getFineractClient().internalCob.updateLoanCobLastDate(loanId,
|
||||
"{\"lastClosedBusinessDate\":\"" + cobDate + "\"}"));
|
||||
}
|
||||
|
||||
public static void reprocessLoan(final Long loanId) {
|
||||
Calls.ok(FineractClientHelper.getFineractClient().internalCob.loanReprocess(loanId));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user