FINERACT-2148: Cumulative Loan - accrual handling in case of charged-off loan
This commit is contained in:
committed by
Adam Saghy
parent
0fc1c3e20e
commit
acabf16003
+5
@@ -18,6 +18,7 @@
|
||||
*/
|
||||
package com.acme.fineract.loan.processor;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.impl.FineractStyleLoanRepaymentScheduleTransactionProcessor;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@@ -28,6 +29,10 @@ public class AcmeLoanRepaymentScheduleTransactionProcessor extends FineractStyle
|
||||
|
||||
public static final String STRATEGY_NAME = "ACME Corp.: standard loan transaction processing strategy";
|
||||
|
||||
public AcmeLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+1
@@ -25,6 +25,7 @@ public enum DefaultLoanProduct implements LoanProduct {
|
||||
LP1_INTEREST_FLAT, //
|
||||
LP1_INTEREST_DECLINING_BALANCE_PERIOD_SAME_AS_PAYMENT, //
|
||||
LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY, //
|
||||
LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_INT_RECALC, //
|
||||
LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_ACCRUAL_ACTIVITY, //
|
||||
LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY, //
|
||||
LP1_1MONTH_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_MONTHLY, //
|
||||
|
||||
+13
@@ -1948,6 +1948,19 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
|
||||
TestContext.INSTANCE.set(
|
||||
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_LEAP_YEAR_INTEREST_RECALCULATION_DAILY,
|
||||
responseLoanProductsRequestLP2AdvancedPaymentInterestEmiActualActualLeapYearInterestRecalculationDaily);
|
||||
|
||||
// LP1 with 12% DECLINING BALANCE interest, interest period: Daily, interest recalculation enabled
|
||||
// (LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_INT_RECALC)
|
||||
final String name81 = DefaultLoanProduct.LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_INT_RECALC.getName();
|
||||
final PostLoanProductsRequest loanProductsRequestInterestDecliningPeriodDailyIntRecalc = loanProductsRequestFactory
|
||||
.defaultLoanProductsRequestLP1InterestDeclining().name(name81).isInterestRecalculationEnabled(true)
|
||||
.preClosureInterestCalculationStrategy(1).rescheduleStrategyMethod(1).interestRecalculationCompoundingMethod(0)
|
||||
.recalculationRestFrequencyType(2).recalculationRestFrequencyInterval(1)
|
||||
.interestCalculationPeriodType(InterestCalculationPeriodTime.DAILY.value).allowPartialPeriodInterestCalcualtion(false);
|
||||
final Response<PostLoanProductsResponse> responseInterestDecliningPeriodDailyIntRecalc = loanProductsApi
|
||||
.createLoanProduct(loanProductsRequestInterestDecliningPeriodDailyIntRecalc).execute();
|
||||
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY_INT_RECALC,
|
||||
responseInterestDecliningPeriodDailyIntRecalc);
|
||||
}
|
||||
|
||||
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
|
||||
|
||||
+1
@@ -68,6 +68,7 @@ public abstract class TestContextKey {
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_REDUCE_NR_INSTALLMENTS = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneRescheduleReduceNrInstallments";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_RESCHEDULE_NEXT_REPAYMENTS = "loanProductCreateResponseLP1InterestDecliningBalanceDailyRecalculationCompoundingNoneRescheduleNextRepayments";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY = "loanProductCreateResponseLP1InterestDecliningPeriodDaily";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY_INT_RECALC = "loanProductCreateResponseLP1InterestDecliningPeriodDailyIntRecalc";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_PERIOD_DAILY_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP1InterestDecliningPeriodDailyAccrualActivity";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_INTEREST_DECLINING_BALANCE_DAILY_RECALCULATION_COMPOUNDING_NONE_ACCRUAL_ACTIVITY = "loanProductCreateResponseLP1InterestDecliningBalanceRecalculationCompoundingNoneAccrualActivity";
|
||||
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION = "loanProductCreateResponseLP2DownPaymentAutoAdvancedPaymentAllocation";
|
||||
|
||||
@@ -847,6 +847,7 @@ Feature: Charge-off
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 22 February 2023 | Accrual | 17.5 | 0.0 | 17.5 | 0.0 | 0.0 | 0.0 |
|
||||
| 22 February 2023 | Charge-off | 1143.0 | 1000.0 | 30.0 | 103.0 | 10.0 | 0.0 |
|
||||
|
||||
@TestRailId:C2761
|
||||
@@ -1204,6 +1205,7 @@ Feature: Charge-off
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 02 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 03 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 05 January 2023 | Accrual | 0.65 | 0.0 | 0.65 | 0.0 | 0.0 | 0.0 |
|
||||
| 05 January 2023 | Charge-off | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
|
||||
@TestRailId:C2780
|
||||
@@ -1234,6 +1236,7 @@ Feature: Charge-off
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 02 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Accrual | 0.66 | 0.0 | 0.66 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Charge-off | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
When Admin sets the business date to "05 January 2023"
|
||||
When Admin runs inline COB job for Loan
|
||||
@@ -1253,8 +1256,9 @@ Feature: Charge-off
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 02 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Accrual | 0.66 | 0.0 | 0.66 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Charge-off | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
| 06 January 2023 | Accrual | 1.31 | 0.0 | 1.31 | 0.0 | 0.0 | 0.0 |
|
||||
| 06 January 2023 | Accrual | 0.65 | 0.0 | 0.65 | 0.0 | 0.0 | 0.0 |
|
||||
Then On Loan Transactions tab the "Charge-off" Transaction with date "04 January 2023" is reverted
|
||||
|
||||
@TestRailId:C2781
|
||||
@@ -1285,6 +1289,7 @@ Feature: Charge-off
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 02 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Accrual | 0.66 | 0.0 | 0.66 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Charge-off | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
When Admin sets the business date to "05 January 2023"
|
||||
When Admin runs inline COB job for Loan
|
||||
@@ -1302,9 +1307,96 @@ Feature: Charge-off
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2023 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 02 January 2023 | Accrual | 0.33 | 0.0 | 0.33 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Accrual | 0.66 | 0.0 | 0.66 | 0.0 | 0.0 | 0.0 |
|
||||
| 04 January 2023 | Charge-off | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
| 06 January 2023 | Repayment | 1010.19 | 1000.0 | 10.19 | 0.0 | 0.0 | 0.0 |
|
||||
|
||||
Scenario: Accrual handling in case of charged-off loan when charge-off behavior is regular, interestRecalculation = true, cumulative loan
|
||||
When Admin sets the business date to "1 January 2024"
|
||||
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 |
|
||||
| LP1_INTEREST_DECLINING_BALANCE_PERIOD_DAILY_INT_RECALC | 01 January 2024 | 100 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 6 | MONTHS | 1 | MONTHS | 6 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
|
||||
And Admin successfully approves the loan on "1 January 2024" with "100" amount and expected disbursement date on "1 January 2024"
|
||||
And Admin successfully disburse the loan on "1 January 2024" with "100" EUR transaction amount
|
||||
When Admin runs inline COB job 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 |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | | 83.59 | 16.41 | 0.59 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.05 | 16.54 | 0.46 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.45 | 16.6 | 0.4 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.74 | 16.71 | 0.29 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.94 | 16.8 | 0.2 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.94 | 0.1 | 0.0 | 0.0 | 17.04 | 0.0 | 0.0 | 0.0 | 17.04 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100 | 2.04 | 0 | 0 | 102.04 | 0 | 0 | 0 | 102.04 |
|
||||
When Admin sets the business date to "14 February 2024"
|
||||
When Admin runs inline COB job for Loan
|
||||
And Admin does charge-off the loan on "14 February 2024"
|
||||
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 |
|
||||
| | | 01 January 2024 | | 100.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2024 | | 83.59 | 16.41 | 0.59 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 2 | 29 | 01 March 2024 | | 67.1 | 16.49 | 0.51 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 3 | 31 | 01 April 2024 | | 50.5 | 16.6 | 0.4 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 4 | 30 | 01 May 2024 | | 33.79 | 16.71 | 0.29 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 5 | 31 | 01 June 2024 | | 16.99 | 16.8 | 0.2 | 0.0 | 0.0 | 17.0 | 0.0 | 0.0 | 0.0 | 17.0 |
|
||||
| 6 | 30 | 01 July 2024 | | 0.0 | 16.99 | 0.1 | 0.0 | 0.0 | 17.09 | 0.0 | 0.0 | 0.0 | 17.09 |
|
||||
Then Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 100 | 2.09 | 0 | 0 | 102.09 | 0 | 0 | 0 | 102.09 |
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 | 0.0 | 0.0 | 100.0 | false | false |
|
||||
| 02 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 03 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 04 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 05 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 06 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 07 January 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 08 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 09 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 10 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 11 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 12 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 13 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 14 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 15 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 16 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 17 January 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 18 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 19 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 20 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 21 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 22 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 23 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 24 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 25 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 26 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 27 January 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 28 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 29 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 30 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 31 January 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 01 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 02 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 03 February 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 04 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 05 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 06 February 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 07 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 08 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 09 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 10 February 2024 | Accrual | 0.01 | 0.0 | 0.01 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 11 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 12 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 13 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 14 February 2024 | Accrual | 0.02 | 0.0 | 0.02 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
| 14 February 2024 | Charge-off | 102.09 | 100.0 | 2.09 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
Then LoanAccrualTransactionCreatedBusinessEvent is raised on "14 February 2024"
|
||||
|
||||
@TestRailId:C2782
|
||||
Scenario: Verify that the accrual of charges is not happened when the loan is charged-off on charge's due date but resumed when the charge-off is reverted
|
||||
When Admin sets the business date to "01 January 2023"
|
||||
|
||||
+3
@@ -606,6 +606,7 @@ Feature: LoanInterestWaiver
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 01 February 2024 | Interest Payment Waiver | 260.0 | 250.0 | 10.0 | 0.0 | 0.0 | 750.0 |
|
||||
| 02 February 2024 | Accrual | 10.34 | 0.0 | 10.34 | 0.0 | 0.0 | 0.0 |
|
||||
| 02 February 2024 | Charge-off | 780.0 | 750.0 | 30.0 | 0.0 | 0.0 | 0.0 |
|
||||
Then Loan Transactions tab has a "DISBURSEMENT" transaction with date "01 January 2024" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
@@ -647,6 +648,7 @@ Feature: LoanInterestWaiver
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 15 January 2024 | Accrual | 4.52 | 0.0 | 4.52 | 0.0 | 0.0 | 0.0 |
|
||||
| 15 January 2024 | Charge-off | 1040.0 | 1000.0 | 40.0 | 0.0 | 0.0 | 0.0 |
|
||||
Then Loan Transactions tab has a "DISBURSEMENT" transaction with date "01 January 2024" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
@@ -673,6 +675,7 @@ Feature: LoanInterestWaiver
|
||||
Then Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance |
|
||||
| 01 January 2024 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 |
|
||||
| 15 January 2024 | Accrual | 4.52 | 0.0 | 4.52 | 0.0 | 0.0 | 0.0 |
|
||||
| 15 January 2024 | Charge-off | 1040.0 | 1000.0 | 40.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 01 February 2024 | Interest Payment Waiver | 260.0 | 250.0 | 10.0 | 0.0 | 0.0 | 750.0 |
|
||||
Then Loan Transactions tab has a "DISBURSEMENT" transaction with date "01 January 2024" which has the following Journal entries:
|
||||
|
||||
+94
-2
@@ -18,8 +18,14 @@
|
||||
*/
|
||||
package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor;
|
||||
|
||||
import static java.math.BigDecimal.ZERO;
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction.accrualAdjustment;
|
||||
import static org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction.accrueTransaction;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.MathContext;
|
||||
import java.time.LocalDate;
|
||||
import java.time.temporal.ChronoUnit;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -28,15 +34,19 @@ import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
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.organisation.monetary.domain.MoneyHelper;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanChargePaidDetail;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.TransactionChangeData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
@@ -62,10 +72,12 @@ import org.springframework.util.CollectionUtils;
|
||||
* @see HeavensFamilyLoanRepaymentScheduleTransactionProcessor
|
||||
* @see CreocoreLoanRepaymentScheduleTransactionProcessor
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implements LoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
public final SingleLoanChargeRepaymentScheduleProcessingWrapper loanChargeProcessor = new SingleLoanChargeRepaymentScheduleProcessingWrapper();
|
||||
public final LoanChargeValidator loanChargeValidator = new LoanChargeValidator();
|
||||
protected final SingleLoanChargeRepaymentScheduleProcessingWrapper loanChargeProcessor = new SingleLoanChargeRepaymentScheduleProcessingWrapper();
|
||||
protected final LoanChargeValidator loanChargeValidator = new LoanChargeValidator();
|
||||
protected final ExternalIdFactory externalIdFactory;
|
||||
|
||||
@Override
|
||||
public boolean accept(String s) {
|
||||
@@ -399,6 +411,12 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
private void recalculateChargeOffTransaction(ChangedTransactionDetail changedTransactionDetail, LoanTransaction loanTransaction,
|
||||
MonetaryCurrency currency, List<LoanRepaymentScheduleInstallment> installments) {
|
||||
final LoanTransaction newLoanTransaction = LoanTransaction.copyTransactionProperties(loanTransaction);
|
||||
|
||||
final BigDecimal newInterest = getInterestTillChargeOffForPeriod(newLoanTransaction.getLoan(),
|
||||
newLoanTransaction.getTransactionDate());
|
||||
createMissingAccrualTransactionDuringChargeOffIfNeeded(newInterest, newLoanTransaction, newLoanTransaction.getTransactionDate(),
|
||||
changedTransactionDetail);
|
||||
|
||||
newLoanTransaction.resetDerivedComponents();
|
||||
// determine how much is outstanding total and breakdown for principal, interest and charges
|
||||
Money principalPortion = Money.zero(currency);
|
||||
@@ -933,4 +951,78 @@ public abstract class AbstractLoanRepaymentScheduleTransactionProcessor implemen
|
||||
}
|
||||
return latestCharge;
|
||||
}
|
||||
|
||||
private BigDecimal getInterestTillChargeOffForPeriod(final Loan loan, final LocalDate chargeOffDate) {
|
||||
BigDecimal interestTillChargeOff = BigDecimal.ZERO;
|
||||
final MonetaryCurrency currency = loan.getCurrency();
|
||||
|
||||
final List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments().stream()
|
||||
.filter(i -> !i.isAdditional()).toList();
|
||||
|
||||
for (LoanRepaymentScheduleInstallment installment : installments) {
|
||||
final boolean isPastPeriod = !installment.getDueDate().isAfter(chargeOffDate);
|
||||
final boolean isInPeriod = !installment.getFromDate().isAfter(chargeOffDate) && installment.getDueDate().isAfter(chargeOffDate);
|
||||
|
||||
BigDecimal interest = BigDecimal.ZERO;
|
||||
|
||||
if (isPastPeriod) {
|
||||
interest = installment.getInterestCharged(currency).minus(installment.getCreditedInterest()).getAmount();
|
||||
} else if (isInPeriod) {
|
||||
final BigDecimal totalInterest = installment.getInterestOutstanding(currency).getAmount();
|
||||
if (LoanChargeOffBehaviour.ZERO_INTEREST.equals(loan.getLoanProductRelatedDetail().getChargeOffBehaviour())
|
||||
|| LoanChargeOffBehaviour.ACCELERATE_MATURITY.equals(loan.getLoanProductRelatedDetail().getChargeOffBehaviour())) {
|
||||
interest = totalInterest;
|
||||
} else {
|
||||
final long totalDaysInPeriod = ChronoUnit.DAYS.between(installment.getFromDate(), installment.getDueDate());
|
||||
final long daysTillChargeOff = ChronoUnit.DAYS.between(installment.getFromDate(), chargeOffDate);
|
||||
final MathContext mc = MoneyHelper.getMathContext();
|
||||
|
||||
interest = Money.of(currency, totalInterest.divide(BigDecimal.valueOf(totalDaysInPeriod), mc)
|
||||
.multiply(BigDecimal.valueOf(daysTillChargeOff), mc), mc).getAmount();
|
||||
}
|
||||
}
|
||||
interestTillChargeOff = interestTillChargeOff.add(interest);
|
||||
}
|
||||
|
||||
return interestTillChargeOff;
|
||||
}
|
||||
|
||||
private void createMissingAccrualTransactionDuringChargeOffIfNeeded(final BigDecimal newInterest,
|
||||
final LoanTransaction chargeOffTransaction, final LocalDate chargeOffDate,
|
||||
final ChangedTransactionDetail changedTransactionDetail) {
|
||||
final Loan loan = chargeOffTransaction.getLoan();
|
||||
final List<LoanRepaymentScheduleInstallment> relevantInstallments = loan.getRepaymentScheduleInstallments().stream()
|
||||
.filter(i -> !i.getFromDate().isAfter(chargeOffDate)).toList();
|
||||
|
||||
if (relevantInstallments.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
final BigDecimal sumOfAccrualsTillChargeOff = loan.getLoanTransactions().stream()
|
||||
.filter(lt -> lt.isAccrual() && !lt.getTransactionDate().isAfter(chargeOffDate) && lt.isNotReversed())
|
||||
.map(lt -> Optional.ofNullable(lt.getInterestPortion()).orElse(BigDecimal.ZERO)).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
final BigDecimal sumOfAccrualAdjustmentsTillChargeOff = loan.getLoanTransactions().stream()
|
||||
.filter(lt -> lt.isAccrualAdjustment() && !lt.getTransactionDate().isAfter(chargeOffDate) && lt.isNotReversed())
|
||||
.map(lt -> Optional.ofNullable(lt.getInterestPortion()).orElse(BigDecimal.ZERO)).reduce(BigDecimal.ZERO, BigDecimal::add);
|
||||
|
||||
final BigDecimal missingAccrualAmount = newInterest.subtract(sumOfAccrualsTillChargeOff).add(sumOfAccrualAdjustmentsTillChargeOff);
|
||||
|
||||
if (missingAccrualAmount.compareTo(BigDecimal.ZERO) == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
final LoanTransaction newAccrualTransaction;
|
||||
|
||||
if (missingAccrualAmount.compareTo(BigDecimal.ZERO) > 0) {
|
||||
newAccrualTransaction = accrueTransaction(loan, loan.getOffice(), chargeOffDate, missingAccrualAmount, missingAccrualAmount,
|
||||
ZERO, ZERO, externalIdFactory.create());
|
||||
} else {
|
||||
newAccrualTransaction = accrualAdjustment(loan, loan.getOffice(), chargeOffDate, missingAccrualAmount.abs(),
|
||||
missingAccrualAmount.abs(), ZERO, ZERO, externalIdFactory.create());
|
||||
}
|
||||
|
||||
changedTransactionDetail.addNewTransactionChangeBeforeExistingOne(new TransactionChangeData(null, newAccrualTransaction),
|
||||
chargeOffTransaction);
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -46,6 +47,10 @@ public class CreocoreLoanRepaymentScheduleTransactionProcessor extends AbstractL
|
||||
|
||||
public static final String STRATEGY_NAME = "Creocore Unique";
|
||||
|
||||
public CreocoreLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -22,6 +22,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -47,6 +48,10 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
|
||||
|
||||
public static final String STRATEGY_NAME = "Due penalty, fee, interest, principal, In advance principal, penalty, fee, interest";
|
||||
|
||||
public DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -22,6 +22,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -47,6 +48,10 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
|
||||
|
||||
public static final String STRATEGY_NAME = "Due penalty, interest, principal, fee, In advance penalty, interest, principal, fee";
|
||||
|
||||
public DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -40,6 +41,10 @@ public class EarlyPaymentLoanRepaymentScheduleTransactionProcessor extends Abstr
|
||||
|
||||
public static final String STRATEGY_NAME = "Early Repayment Strategy";
|
||||
|
||||
public EarlyPaymentLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -46,6 +47,10 @@ public class FineractStyleLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
|
||||
public static final String STRATEGY_NAME = "Penalties, Fees, Interest, Principal order";
|
||||
|
||||
public FineractStyleLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -22,6 +22,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -48,6 +49,10 @@ public class HeavensFamilyLoanRepaymentScheduleTransactionProcessor extends Abst
|
||||
|
||||
public static final String STRATEGY_NAME = "HeavensFamily Unique";
|
||||
|
||||
public HeavensFamilyLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -41,6 +42,10 @@ public class InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
|
||||
public static final String STRATEGY_NAME = "Interest, Principal, Penalties, Fees Order";
|
||||
|
||||
public InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -21,6 +21,7 @@ package org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.im
|
||||
import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -41,6 +42,10 @@ public class PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionPr
|
||||
|
||||
public static final String STRATEGY_NAME = "Principal, Interest, Penalties, Fees Order";
|
||||
|
||||
public PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+5
@@ -22,6 +22,7 @@ import java.time.LocalDate;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
|
||||
@@ -50,6 +51,10 @@ public class RBILoanRepaymentScheduleTransactionProcessor extends AbstractLoanRe
|
||||
|
||||
public static final String STRATEGY_NAME = "Overdue/Due Fee/Int,Principal";
|
||||
|
||||
public RBILoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
return STRATEGY_CODE;
|
||||
|
||||
+8
-3
@@ -54,7 +54,6 @@ import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.NotImplementedException;
|
||||
@@ -107,7 +106,6 @@ import org.springframework.transaction.annotation.Propagation;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Slf4j
|
||||
@RequiredArgsConstructor
|
||||
public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRepaymentScheduleTransactionProcessor {
|
||||
|
||||
public static final String ADVANCED_PAYMENT_ALLOCATION_STRATEGY = "advanced-payment-allocation-strategy";
|
||||
@@ -116,7 +114,14 @@ public class AdvancedPaymentScheduleTransactionProcessor extends AbstractLoanRep
|
||||
private final EMICalculator emiCalculator;
|
||||
private final LoanRepositoryWrapper loanRepositoryWrapper;
|
||||
private final InterestRefundService interestRefundService;
|
||||
private final ExternalIdFactory externalIdFactory;
|
||||
|
||||
public AdvancedPaymentScheduleTransactionProcessor(EMICalculator emiCalculator, LoanRepositoryWrapper loanRepositoryWrapper,
|
||||
InterestRefundService interestRefundService, ExternalIdFactory externalIdFactory) {
|
||||
super(externalIdFactory);
|
||||
this.emiCalculator = emiCalculator;
|
||||
this.loanRepositoryWrapper = loanRepositoryWrapper;
|
||||
this.interestRefundService = interestRefundService;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode() {
|
||||
|
||||
+26
-18
@@ -46,56 +46,64 @@ public class LoanAccountAutoStarter {
|
||||
|
||||
@Bean
|
||||
@Conditional(CreocoreLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public CreocoreLoanRepaymentScheduleTransactionProcessor creocoreLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new CreocoreLoanRepaymentScheduleTransactionProcessor();
|
||||
public CreocoreLoanRepaymentScheduleTransactionProcessor creocoreLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new CreocoreLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(EarlyRepaymentLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public EarlyPaymentLoanRepaymentScheduleTransactionProcessor earlyPaymentLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new EarlyPaymentLoanRepaymentScheduleTransactionProcessor();
|
||||
public EarlyPaymentLoanRepaymentScheduleTransactionProcessor earlyPaymentLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new EarlyPaymentLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(MifosStandardLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public FineractStyleLoanRepaymentScheduleTransactionProcessor fineractStyleLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new FineractStyleLoanRepaymentScheduleTransactionProcessor();
|
||||
public FineractStyleLoanRepaymentScheduleTransactionProcessor fineractStyleLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new FineractStyleLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(HeavensFamilyLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public HeavensFamilyLoanRepaymentScheduleTransactionProcessor heavensFamilyLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new HeavensFamilyLoanRepaymentScheduleTransactionProcessor();
|
||||
public HeavensFamilyLoanRepaymentScheduleTransactionProcessor heavensFamilyLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new HeavensFamilyLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(InterestPrincipalPenaltiesFeesLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor interestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor();
|
||||
public InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor interestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new InterestPrincipalPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(PrincipalInterestPenaltiesFeesLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor principalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor();
|
||||
public PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor principalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new PrincipalInterestPenaltyFeesOrderLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(RBIIndiaLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public RBILoanRepaymentScheduleTransactionProcessor rbiLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new RBILoanRepaymentScheduleTransactionProcessor();
|
||||
public RBILoanRepaymentScheduleTransactionProcessor rbiLoanRepaymentScheduleTransactionProcessor(ExternalIdFactory externalIdFactory) {
|
||||
return new RBILoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor duePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor();
|
||||
public DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor duePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
@Conditional(DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessorCondition.class)
|
||||
public DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor duePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor() {
|
||||
return new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor();
|
||||
public DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor duePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(
|
||||
ExternalIdFactory externalIdFactory) {
|
||||
return new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(externalIdFactory);
|
||||
}
|
||||
|
||||
@Bean
|
||||
|
||||
+1
-1
@@ -99,7 +99,7 @@ public class DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactio
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor();
|
||||
underTest = new DuePenFeeIntPriInAdvancePriPenFeeIntLoanRepaymentScheduleTransactionProcessor(null);
|
||||
Mockito.reset(charges, transactionMappings);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
|
||||
+1
-1
@@ -100,7 +100,7 @@ public class DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactio
|
||||
|
||||
@BeforeEach
|
||||
public void setUp() {
|
||||
underTest = new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor();
|
||||
underTest = new DuePenIntPriFeeInAdvancePenIntPriFeeLoanRepaymentScheduleTransactionProcessor(null);
|
||||
Mockito.reset(charges, transactionMappings);
|
||||
|
||||
ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "default", "Default", "Asia/Kolkata", null));
|
||||
|
||||
+17
-12
@@ -780,8 +780,9 @@ public class LoanChargeOffAccountingTest extends BaseLoanIntegrationTest {
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||
assertTrue(loanDetails.getTransactions().get(0).getType().getDisbursement());
|
||||
assertTrue(loanDetails.getTransactions().get(1).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getChargeoff());
|
||||
assertEquals(3, loanDetails.getTransactions().size());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getChargeoff());
|
||||
assertEquals(4, loanDetails.getTransactions().size());
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 9, 8));
|
||||
inlineLoanCOBHelper.executeInlineCOB(List.of(loanId.longValue()));
|
||||
@@ -789,8 +790,9 @@ public class LoanChargeOffAccountingTest extends BaseLoanIntegrationTest {
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||
assertTrue(loanDetails.getTransactions().get(0).getType().getDisbursement());
|
||||
assertTrue(loanDetails.getTransactions().get(1).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getChargeoff());
|
||||
assertEquals(3, loanDetails.getTransactions().size());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getChargeoff());
|
||||
assertEquals(4, loanDetails.getTransactions().size());
|
||||
|
||||
loanTransactionHelper.undoChargeOffLoan((long) loanId, new PostLoansLoanIdTransactionsRequest());
|
||||
// generate accrual again
|
||||
@@ -799,9 +801,10 @@ public class LoanChargeOffAccountingTest extends BaseLoanIntegrationTest {
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||
assertTrue(loanDetails.getTransactions().get(0).getType().getDisbursement());
|
||||
assertTrue(loanDetails.getTransactions().get(1).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getAccrual());
|
||||
assertEquals(4, loanDetails.getTransactions().size());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(4).getType().getAccrual());
|
||||
assertEquals(5, loanDetails.getTransactions().size());
|
||||
|
||||
BusinessDateHelper.updateBusinessDate(requestSpec, responseSpec, BusinessDateType.BUSINESS_DATE, LocalDate.of(2020, 9, 10));
|
||||
|
||||
@@ -815,11 +818,13 @@ public class LoanChargeOffAccountingTest extends BaseLoanIntegrationTest {
|
||||
loanDetails = loanTransactionHelper.getLoanDetails(loanId.longValue());
|
||||
assertTrue(loanDetails.getTransactions().get(0).getType().getDisbursement());
|
||||
assertTrue(loanDetails.getTransactions().get(1).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(4).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(5).getType().getRepayment());
|
||||
assertEquals(6, loanDetails.getTransactions().size());
|
||||
assertTrue(loanDetails.getTransactions().get(2).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(3).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(4).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(5).getType().getAccrual());
|
||||
assertTrue(loanDetails.getTransactions().get(6).getType().getChargeoff());
|
||||
assertTrue(loanDetails.getTransactions().get(7).getType().getRepayment());
|
||||
assertEquals(8, loanDetails.getTransactions().size());
|
||||
} finally {
|
||||
globalConfigurationHelper.updateGlobalConfiguration(GlobalConfigurationConstants.ENABLE_BUSINESS_DATE,
|
||||
new PutGlobalConfigurationsRequest().enabled(false));
|
||||
|
||||
Reference in New Issue
Block a user