This is an automated email from the ASF dual-hosted git repository.
adamsaghy pushed a commit to branch develop
in repository https://gitbox.apache.org/repos/asf/fineract.git
The following commit(s) were added to refs/heads/develop by this push:
new 48a0630b4 FINERACT-2081: Adding additional E2E tests to improve test
coverage - pt1: stepdef files
48a0630b4 is described below
commit 48a0630b4712031a5f6b8b90fbec7c9b4f4a7d41
Author: Peter Kovacs <[email protected]>
AuthorDate: Tue Feb 11 11:07:22 2025 +0100
FINERACT-2081: Adding additional E2E tests to improve test coverage - pt1:
stepdef files
---
.../fineract/test/config/CacheConfiguration.java | 3 +-
.../fineract/test/data/ChargeOffBehaviour.java | 30 ++
.../fineract/test/data/codevalue/CodeValue.java | 24 ++
.../test/data/codevalue/CodeValueResolver.java | 58 +++
.../DefaultCodeValue.java} | 26 +-
.../apache/fineract/test/data/job/DefaultJob.java | 4 +-
.../test/data/loanproduct/DefaultLoanProduct.java | 13 +
.../test/factory/LoanProductsRequestFactory.java | 141 +++++++
.../fineract/test/factory/LoanRequestFactory.java | 6 +
.../apache/fineract/test/helper/CodeHelper.java | 4 +-
.../fineract/test/helper/ErrorMessageHelper.java | 12 +
.../global/CodeGlobalInitializerStep.java | 6 +
.../global/LoanProductGlobalInitializerStep.java | 412 +++++++++++++++++++--
.../test/messaging/event/EventCheckHelper.java | 8 +
.../LoanChargeAdjustmentPostBusinessEvent.java | 27 ++
.../test/stepdef/common/SchedulerStepDef.java | 10 +
.../stepdef/loan/LoanInterestPauseStepDef.java | 2 +-
.../test/stepdef/loan/LoanRepaymentStepDef.java | 38 ++
.../fineract/test/stepdef/loan/LoanStepDef.java | 219 ++++++++++-
.../fineract/test/support/TestContextKey.java | 19 +-
.../resources/features/LoanInterestPause.feature | 14 +-
.../test/resources/features/LoanProduct.feature | 12 +-
22 files changed, 1026 insertions(+), 62 deletions(-)
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/config/CacheConfiguration.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/config/CacheConfiguration.java
index a9a3e485e..6d1fe56bc 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/config/CacheConfiguration.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/config/CacheConfiguration.java
@@ -36,7 +36,8 @@ public class CacheConfiguration {
simpleCacheManager.setCaches(List.of(new
ConcurrentMapCache("paymentTypesByName"), //
new ConcurrentMapCache("jobsByShortName"), //
new ConcurrentMapCache("loanProductsByName"), //
- new ConcurrentMapCache("accountTypesByName")));//
+ new ConcurrentMapCache("accountTypesByName"), //
+ new ConcurrentMapCache("codeValuesByName")));//
return simpleCacheManager;
}
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/ChargeOffBehaviour.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/ChargeOffBehaviour.java
new file mode 100644
index 000000000..5d736ad7e
--- /dev/null
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/ChargeOffBehaviour.java
@@ -0,0 +1,30 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.test.data;
+
+public enum ChargeOffBehaviour {
+
+ ZERO_INTEREST("ZERO_INTEREST"), REGULAR("REGULAR");
+
+ public final String value;
+
+ ChargeOffBehaviour(String value) {
+ this.value = value;
+ }
+}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValue.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValue.java
new file mode 100644
index 000000000..a2b52f254
--- /dev/null
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValue.java
@@ -0,0 +1,24 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.test.data.codevalue;
+
+public interface CodeValue {
+
+ String getName();
+}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValueResolver.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValueResolver.java
new file mode 100644
index 000000000..9c93cd56c
--- /dev/null
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeValueResolver.java
@@ -0,0 +1,58 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.test.data.codevalue;
+
+import java.io.IOException;
+import java.util.List;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.fineract.client.models.GetCodeValuesDataResponse;
+import org.apache.fineract.client.services.CodeValuesApi;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Component;
+import retrofit2.Response;
+
+@Component
+@RequiredArgsConstructor
+@Slf4j
+public class CodeValueResolver {
+
+ private final CodeValuesApi codeValuesApi;
+
+ @Cacheable(key = "#codeValue.getName()", value = "codeValuesByName")
+ public long resolve(Long codeId, CodeValue codeValue) {
+ try {
+ String codeValueName = codeValue.getName();
+
+ log.debug("Resolving code value by code id and name [{}]",
codeValue);
+ Response<List<GetCodeValuesDataResponse>> response =
codeValuesApi.retrieveAllCodeValues(codeId).execute();
+ if (!response.isSuccessful()) {
+ throw new IllegalStateException("Unable to get payment types.
Status code was HTTP " + response.code());
+ }
+
+ List<GetCodeValuesDataResponse> codeValuesResponses =
response.body();
+ GetCodeValuesDataResponse foundPtr =
codeValuesResponses.stream().filter(ptr ->
codeValueName.equals(ptr.getName())).findAny()
+ .orElseThrow(() -> new IllegalArgumentException("Payment
type [%s] not found".formatted(codeValueName)));
+
+ return foundPtr.getId();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java
similarity index 55%
copy from
fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
copy to
fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java
index 1798e8783..c117080b2 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java
@@ -16,32 +16,24 @@
* specific language governing permissions and limitations
* under the License.
*/
-package org.apache.fineract.test.data.job;
+package org.apache.fineract.test.data.codevalue;
-public enum DefaultJob implements Job {
+public enum DefaultCodeValue implements CodeValue {
- ADD_ACCRUAL_TRANSACTIONS("Add Accrual Transactions", "LA_AATR"), //
- ADD_PERIODIC_ACCRUAL_TRANSACTIONS("Add Periodic Accrual Transactions",
"ACC_APTR"), //
- INCREASE_BUSINESS_DAY("Increase Business Date by 1 day", "BDT_INC1"), //
- LOAN_DELINQUENCY_CLASSIFICATION("Loan Delinquency Classification",
"LA_DECL"), //
- LOAN_COB("Loan COB", "LA_ECOB"), //
- ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting", "ACC_ACPO");
+ // Charge-off reason
+ FRAUD("Fraud"), DELINQUENT("Delinquent"), OTHER("Other");
private final String customName;
- private final String shortName;
- DefaultJob(String customName, String shortName) {
+ DefaultCodeValue(String customName) {
this.customName = customName;
- this.shortName = shortName;
}
@Override
public String getName() {
- return customName;
- }
-
- @Override
- public String getShortName() {
- return shortName;
+ if (customName != null) {
+ return customName;
+ }
+ return name();
}
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
index 1798e8783..0112e9963 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/job/DefaultJob.java
@@ -25,7 +25,9 @@ public enum DefaultJob implements Job {
INCREASE_BUSINESS_DAY("Increase Business Date by 1 day", "BDT_INC1"), //
LOAN_DELINQUENCY_CLASSIFICATION("Loan Delinquency Classification",
"LA_DECL"), //
LOAN_COB("Loan COB", "LA_ECOB"), //
- ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting", "ACC_ACPO");
+ ACCRUAL_ACTIVITY_POSTING("Accrual Activity Posting", "ACC_ACPO"),
ADD_ACCRUAL_TRANSACTIONS_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS(
+ "Add Accrual Transactions For Loans With Income Posted As
Transactions",
+ "LA_AATR"), RECALCULATE_INTEREST_FOR_LOANS("Recalculate Interest
For Loans", "LA_RINT");
private final String customName;
private final String shortName;
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
index 16861dfed..7b3557afa 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/loanproduct/DefaultLoanProduct.java
@@ -53,10 +53,13 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_DOWNPAYMENT_AUTO_ADVANCED_PAYMENT_ALLOCATION_REPAYMENT_START_SUBMITTED, //
LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC, //
LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT,
//
+
LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY, //
+
LP2_ADV_PYMNT_INTEREST_DAILY_AUTO_DOWNPAYMENT_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SARP_TILL_PRECLOSE,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_REST_FREQUENCY_DATE,
//
@@ -64,9 +67,11 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_ADV_CUSTOM_PAYMENT_ALLOC_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE, //
+
LP2_ADV_PAYMENT_ALLOC_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_EMI_360_30_MULTIDISBURSE,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL, //
+ LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_ACTUAL, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND, //
LP1_ADV_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, //
LP2_ADV_CUSTOM_PMT_ALLOC_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL, //
@@ -74,8 +79,16 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_IR_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT_STRATEGY,
//
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_INTEREST_RECALCULATION,
//
LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF, //
LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR, //
+ LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF, //
LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING,
//
+ LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL,
//
+ LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL,
//
+
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY, //
LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR, //
LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST, //
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java
index beb83efd5..5dc5cf2fe 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanProductsRequestFactory.java
@@ -29,10 +29,12 @@ import org.apache.fineract.client.models.ChargeData;
import org.apache.fineract.client.models.ChargeToGLAccountMapper;
import org.apache.fineract.client.models.GetLoanFeeToIncomeAccountMappings;
import
org.apache.fineract.client.models.GetLoanPaymentChannelToFundSourceMappings;
+import
org.apache.fineract.client.models.PostChargeOffReasonToExpenseAccountMappings;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.test.data.AccountingRule;
import org.apache.fineract.test.data.AdvancePaymentsAdjustmentType;
import org.apache.fineract.test.data.AmortizationType;
+import org.apache.fineract.test.data.ChargeOffBehaviour;
import org.apache.fineract.test.data.DaysInMonthType;
import org.apache.fineract.test.data.DaysInYearType;
import org.apache.fineract.test.data.DelinquencyBucket;
@@ -48,9 +50,13 @@ import org.apache.fineract.test.data.RepaymentFrequencyType;
import org.apache.fineract.test.data.TransactionProcessingStrategyCode;
import org.apache.fineract.test.data.accounttype.AccountTypeResolver;
import org.apache.fineract.test.data.accounttype.DefaultAccountType;
+import org.apache.fineract.test.data.codevalue.CodeValueResolver;
+import org.apache.fineract.test.data.codevalue.DefaultCodeValue;
import org.apache.fineract.test.data.paymenttype.DefaultPaymentType;
import org.apache.fineract.test.data.paymenttype.PaymentTypeResolver;
+import org.apache.fineract.test.helper.CodeHelper;
import org.apache.fineract.test.helper.Utils;
+import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
@@ -59,6 +65,10 @@ public class LoanProductsRequestFactory {
private final PaymentTypeResolver paymentTypeResolver;
private final AccountTypeResolver accountTypeResolver;
+ private final CodeValueResolver codeValueResolver;
+
+ @Autowired
+ private CodeHelper codeHelper;
public static final String NAME_PREFIX = "LP1-";
public static final String NAME_PREFIX_LP2 = "LP2-";
@@ -112,6 +122,7 @@ public class LoanProductsRequestFactory {
public static final Integer FREQUENCY_FOR_COMPOUNDING_MONTHLY =
RecalculationCompoundingFrequencyType.MONTHLY.value;
public static final Integer
FREQUENCY_FOR_RECALCULATE_OUTSTANDING_PRINCIPAL_SAME_AS_REPAYMENT =
RecalculationRestFrequencyType.SAME_AS_REPAYMENT.value;
public static final Integer FREQUENCY_FOR_RECALCULATE_OUTSTANDING_DAILY =
RecalculationRestFrequencyType.DAILY.value;
+ public static final String CHARGE_OFF_REASONS = "ChargeOffReasons";
public PostLoanProductsRequest defaultLoanProductsRequestLP1() {
String name = Utils.randomNameGenerator(NAME_PREFIX, 4);
@@ -1110,4 +1121,134 @@ public class LoanProductsRequestFactory {
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))//
.incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));//
}
+
+ public PostLoanProductsRequest
defaultLoanProductsRequestLP2EmiWithChargeOff() {
+ String name = Utils.randomNameGenerator(NAME_PREFIX_LP2_EMI, 4);
+ String shortName = Utils.randomNameGenerator(SHORT_NAME_PREFIX_EMI, 3);
+
+ List<Integer> principalVariationsForBorrowerCycle = new ArrayList<>();
+ List<Integer> numberOfRepaymentVariationsForBorrowerCycle = new
ArrayList<>();
+ List<Integer> interestRateVariationsForBorrowerCycle = new
ArrayList<>();
+ List<ChargeData> charges = new ArrayList<>();
+ List<ChargeToGLAccountMapper> penaltyToIncomeAccountMappings = new
ArrayList<>();
+ List<GetLoanFeeToIncomeAccountMappings> feeToIncomeAccountMappings =
new ArrayList<>();
+
+ List<GetLoanPaymentChannelToFundSourceMappings>
paymentChannelToFundSourceMappings = new ArrayList<>();
+ GetLoanPaymentChannelToFundSourceMappings
loanPaymentChannelToFundSourceMappings = new
GetLoanPaymentChannelToFundSourceMappings();
+
loanPaymentChannelToFundSourceMappings.fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.FUND_RECEIVABLES));
+
loanPaymentChannelToFundSourceMappings.paymentTypeId(paymentTypeResolver.resolve(DefaultPaymentType.MONEY_TRANSFER));
+
paymentChannelToFundSourceMappings.add(loanPaymentChannelToFundSourceMappings);
+
+ Long chargeOffReasonId =
codeHelper.retrieveCodeByName(CHARGE_OFF_REASONS).getId();
+
+ List<PostChargeOffReasonToExpenseAccountMappings>
chargeOffReasonToExpenseAccountMappings = new ArrayList<>();
+ PostChargeOffReasonToExpenseAccountMappings chargeOffFraudReason = new
PostChargeOffReasonToExpenseAccountMappings();
+ PostChargeOffReasonToExpenseAccountMappings chargeOffDelinquentReason
= new PostChargeOffReasonToExpenseAccountMappings();
+ PostChargeOffReasonToExpenseAccountMappings chargeOffOtherReason = new
PostChargeOffReasonToExpenseAccountMappings();
+
chargeOffFraudReason.chargeOffReasonCodeValueId(codeValueResolver.resolve(chargeOffReasonId,
DefaultCodeValue.FRAUD));
+
chargeOffFraudReason.expenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD));
+
chargeOffDelinquentReason.chargeOffReasonCodeValueId(codeValueResolver.resolve(chargeOffReasonId,
DefaultCodeValue.DELINQUENT));
+
chargeOffDelinquentReason.expenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT));
+
chargeOffOtherReason.chargeOffReasonCodeValueId(codeValueResolver.resolve(chargeOffReasonId,
DefaultCodeValue.OTHER));
+
chargeOffOtherReason.expenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT));
+ chargeOffReasonToExpenseAccountMappings.add(chargeOffFraudReason);
+ chargeOffReasonToExpenseAccountMappings.add(chargeOffDelinquentReason);
+ chargeOffReasonToExpenseAccountMappings.add(chargeOffOtherReason);
+
+ return new PostLoanProductsRequest()//
+ .name(name)//
+ .shortName(shortName)//
+ .description(DESCRIPTION_LP2_EMI)//
+ .loanScheduleType("PROGRESSIVE") //
+
.interestCalculationPeriodType(InterestCalculationPeriodTime.DAILY.value)//
+
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())//
+ .fundId(FUND_ID)//
+ .startDate(null)//
+ .closeDate(null)//
+ .includeInBorrowerCycle(false)//
+ .currencyCode(CURRENCY_CODE)//
+ .digitsAfterDecimal(2)//
+ .inMultiplesOf(0)//
+ .useBorrowerCycle(false)//
+ .minPrincipal(10.0)//
+ .principal(1000.0)//
+ .maxPrincipal(10000.0)//
+ .minNumberOfRepayments(1)//
+ .numberOfRepayments(4)//
+ .maxNumberOfRepayments(30)//
+ .isLinkedToFloatingInterestRates(false)//
+ .minInterestRatePerPeriod((double) 0)//
+ .interestRatePerPeriod((double) 12)//
+ .maxInterestRatePerPeriod((double) 60)//
+ .interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_YEAR)//
+ .repaymentEvery(15)//
+ .repaymentStartDateType(1)//
+ .repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_DAYS)//
+
.principalVariationsForBorrowerCycle(principalVariationsForBorrowerCycle)//
+
.numberOfRepaymentVariationsForBorrowerCycle(numberOfRepaymentVariationsForBorrowerCycle)//
+
.interestRateVariationsForBorrowerCycle(interestRateVariationsForBorrowerCycle)//
+ .amortizationType(AMORTIZATION_TYPE)//
+ .interestType(INTEREST_TYPE_DECLINING_BALANCE)//
+ .isEqualAmortization(false)//
+
.interestCalculationPeriodType(INTEREST_CALCULATION_PERIOD_TYPE_DAILY)//
+
.transactionProcessingStrategyCode(TRANSACTION_PROCESSING_STRATEGY_CODE_ADVANCED)//
+ .daysInYearType(DAYS_IN_YEAR_TYPE)//
+ .daysInMonthType(DAYS_IN_MONTH_TYPE)//
+ .canDefineInstallmentAmount(true)//
+ .graceOnArrearsAgeing(3)//
+ .overdueDaysForNPA(179)//
+ .accountMovesOutOfNPAOnlyOnArrearsCompletion(false)//
+ .principalThresholdForLastInstallment(50)//
+ .allowVariableInstallments(false)//
+ .canUseForTopup(false)//
+
+ .chargeOffBehaviour(ChargeOffBehaviour.ZERO_INTEREST.value)
+
.chargeOffReasonToExpenseAccountMappings(chargeOffReasonToExpenseAccountMappings)
+
+ .isInterestRecalculationEnabled(false)//
+ .holdGuaranteeFunds(false)//
+ .multiDisburseLoan(false)//
+ .allowAttributeOverrides(new AllowAttributeOverrides()//
+ .amortizationType(true)//
+ .interestType(true)//
+ .transactionProcessingStrategyCode(true)//
+ .interestCalculationPeriodType(true)//
+ .inArrearsTolerance(true)//
+ .repaymentEvery(true)//
+ .graceOnPrincipalAndInterestPayment(true)//
+ .graceOnArrearsAgeing(true))//
+ .allowPartialPeriodInterestCalcualtion(false)//
+ .maxTrancheCount(10)//
+ .outstandingLoanBalance(10000.0)//
+ .charges(charges)//
+ .accountingRule(LOAN_ACCOUNTING_RULE)//
+
.fundSourceAccountId(accountTypeResolver.resolve(DefaultAccountType.SUSPENSE_CLEARING_ACCOUNT))//
+
.loanPortfolioAccountId(accountTypeResolver.resolve(DefaultAccountType.LOANS_RECEIVABLE))//
+
.transfersInSuspenseAccountId(accountTypeResolver.resolve(DefaultAccountType.TRANSFER_IN_SUSPENSE_ACCOUNT))//
+
.interestOnLoanAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME))//
+
.incomeFromFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
+
.incomeFromPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_INCOME))//
+
.incomeFromRecoveryAccountId(accountTypeResolver.resolve(DefaultAccountType.RECOVERIES))//
+
.writeOffAccountId(accountTypeResolver.resolve(DefaultAccountType.WRITTEN_OFF))//
+
.overpaymentLiabilityAccountId(accountTypeResolver.resolve(DefaultAccountType.OVERPAYMENT_ACCOUNT))//
+
.receivableInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
+
.receivableFeeAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
+
.receivablePenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_FEE_RECEIVABLE))//
+ .dateFormat(DATE_FORMAT)//
+ .locale(LOCALE_EN)//
+ .disallowExpectedDisbursements(false)//
+ .delinquencyBucketId(DELINQUENCY_BUCKET_ID.longValue())//
+
.goodwillCreditAccountId(accountTypeResolver.resolve(DefaultAccountType.GOODWILL_EXPENSE_ACCOUNT))//
+
.incomeFromGoodwillCreditInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME_CHARGE_OFF))//
+
.incomeFromGoodwillCreditFeesAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
+
.incomeFromGoodwillCreditPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
+
.paymentChannelToFundSourceMappings(paymentChannelToFundSourceMappings)//
+
.penaltyToIncomeAccountMappings(penaltyToIncomeAccountMappings)//
+ .feeToIncomeAccountMappings(feeToIncomeAccountMappings)//
+
.incomeFromChargeOffInterestAccountId(accountTypeResolver.resolve(DefaultAccountType.INTEREST_INCOME_CHARGE_OFF))//
+
.incomeFromChargeOffFeesAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF))//
+
.chargeOffExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT))//
+
.chargeOffFraudExpenseAccountId(accountTypeResolver.resolve(DefaultAccountType.CREDIT_LOSS_BAD_DEBT_FRAUD))//
+
.incomeFromChargeOffPenaltyAccountId(accountTypeResolver.resolve(DefaultAccountType.FEE_CHARGE_OFF));//
+ }
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java
index c6e604b58..29fbe7a57 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/factory/LoanRequestFactory.java
@@ -22,6 +22,7 @@ import java.math.BigDecimal;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import lombok.RequiredArgsConstructor;
+import org.apache.fineract.client.models.InterestPauseRequestDto;
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest;
import org.apache.fineract.client.models.PostLoansLoanIdRequest;
@@ -279,4 +280,9 @@ public class LoanRequestFactory {
return new
PostLoansLoanIdTransactionsRequest().transactionDate(DEFAULT_TRANSACTION_DATE).dateFormat(DATE_FORMAT)
.locale(DEFAULT_LOCALE).note("Write Off");
}
+
+ public static InterestPauseRequestDto defaultInterestPauseRequest() {
+ return new
InterestPauseRequestDto().dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE).startDate(DEFAULT_TRANSACTION_DATE)
+ .endDate(DEFAULT_TRANSACTION_DATE);
+ }
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/CodeHelper.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/CodeHelper.java
index ff01ac874..8d6203cc2 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/CodeHelper.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/CodeHelper.java
@@ -20,6 +20,7 @@ package org.apache.fineract.test.helper;
import java.io.IOException;
import lombok.RequiredArgsConstructor;
+import lombok.SneakyThrows;
import org.apache.fineract.client.models.GetCodesResponse;
import org.apache.fineract.client.models.PostCodeValueDataResponse;
import org.apache.fineract.client.models.PostCodeValuesDataRequest;
@@ -54,7 +55,8 @@ public class CodeHelper {
return codeValuesApi.createCodeValue(codeId, new
PostCodeValuesDataRequest().name(stateName)).execute();
}
- public GetCodesResponse retrieveCodeByName(String name) throws IOException
{
+ @SneakyThrows
+ public GetCodesResponse retrieveCodeByName(String name) {
return codesApi.retrieveCodes().execute().body().stream().filter(r ->
name.equals(r.getName())).findAny()
.orElseThrow(() -> new IllegalArgumentException("Code with
name " + name + " has not been found"));
}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java
index 4bc6dbdfe..5a3365a29 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java
@@ -71,6 +71,10 @@ public final class ErrorMessageHelper {
return "Loan disbursal amount can't be greater than maximum applied
loan amount calculation. Total disbursed amount: [0-9]* Maximum disbursal
amount: [0-9]*";
}
+ public static String disburseChargedOffLoanFailure() {
+ return "Loan: [0-9]* disbursement is not allowed on charged-off loan.";
+ }
+
public static String loanSubmitDateInFutureFailureMsg() {
return "The date on which a loan is submitted cannot be in the
future.";
}
@@ -273,6 +277,10 @@ public final class ErrorMessageHelper {
expectedToStr);
}
+ public static String transactionHasNullResourceValue(String
transactionType, String resourceName) {
+ return String.format("The transaction %s should has non-null value for
%s, but it is null.", transactionType, resourceName);
+ }
+
public static String wrongDataInChargesName(String actual, String
expected) {
return String.format("Wrong data in Charges / Name. Actual value is:
%s - But expected value is: %s", actual, expected);
}
@@ -449,6 +457,10 @@ public final class ErrorMessageHelper {
return String.format("Idempotency key is not matching: Actual value
is: %s - But expected value is: %s", actual, expected);
}
+ public static String wrongNumberOfLinesInRepaymentSchedule(int actual, int
expected) {
+ return wrongNumberOfLinesInRepaymentSchedule(null, actual, expected);
+ }
+
public static String wrongNumberOfLinesInRepaymentSchedule(String
resourceId, int actual, int expected) {
return String.format("Number of lines in Repayment schedule of
resource %s is not correct. " //
+ "Actual value is: %s - But expected value is: %s",
resourceId, actual, expected);
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java
index 4cfe0907a..f269f9df9 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java
@@ -53,6 +53,9 @@ public class CodeGlobalInitializerStep implements
FineractGlobalInitializerStep
public static final Long CODE_VALUE_FINANCIAL_INSTRUMENT_ID = 39L;
public static final String CODE_VALUE_FINANCIAL_INSTRUMENT_DEBIT =
"debit_card";
public static final String CODE_VALUE_FINANCIAL_INSTRUMENT_CREDIT =
"credit_card";
+ public static final String CODE_VALUE_FINANCIAL_INSTRUMENT_FRAUD = "Fraud";
+ public static final String CODE_VALUE_FINANCIAL_INSTRUMENT_DELINQUENT =
"Delinquent";
+ public static final String CODE_VALUE_FINANCIAL_INSTRUMENT_OTHER = "Other";
public static final Long CODE_VALUE_TRANSACTION_TYPE_ID = 40L;
public static final String CODE_VALUE_TRANSACTION_TYPE_SCHEDULED_PAYMENT =
"scheduled_payment";
public static final Long CODE_VALUE_BANKRUPTCY_TAG_ID = 41L;
@@ -138,6 +141,9 @@ public class CodeGlobalInitializerStep implements
FineractGlobalInitializerStep
List<String> financialInstrumentNames = new ArrayList<>();
financialInstrumentNames.add(CODE_VALUE_FINANCIAL_INSTRUMENT_DEBIT);
financialInstrumentNames.add(CODE_VALUE_FINANCIAL_INSTRUMENT_CREDIT);
+ financialInstrumentNames.add(CODE_VALUE_FINANCIAL_INSTRUMENT_FRAUD);
+
financialInstrumentNames.add(CODE_VALUE_FINANCIAL_INSTRUMENT_DELINQUENT);
+ financialInstrumentNames.add(CODE_VALUE_FINANCIAL_INSTRUMENT_OTHER);
createCodeValues(CODE_VALUE_FINANCIAL_INSTRUMENT_ID,
financialInstrumentNames);
// transaction type
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
index ddda52307..a2d2c0b8b 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java
@@ -19,7 +19,10 @@
package org.apache.fineract.test.initializer.global;
import static
org.apache.fineract.test.data.TransactionProcessingStrategyCode.ADVANCED_PAYMENT_ALLOCATION;
+import static
org.apache.fineract.test.factory.LoanProductsRequestFactory.INTEREST_CALCULATION_PERIOD_TYPE_SAME_AS_REPAYMENT;
+import static
org.apache.fineract.test.factory.LoanProductsRequestFactory.INTEREST_RATE_FREQUENCY_TYPE_MONTH;
import static
org.apache.fineract.test.factory.LoanProductsRequestFactory.INTEREST_RATE_FREQUENCY_TYPE_WHOLE_TERM;
+import static
org.apache.fineract.test.factory.LoanProductsRequestFactory.REPAYMENT_FREQUENCY_TYPE_MONTHS;
import java.math.BigDecimal;
import java.util.ArrayList;
@@ -1089,14 +1092,112 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE,
responseLoanProductsRequestLP2AdvCustomPaymentAllocationInterestRecalculationDaily36030MultiDisburse);
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30
+ // + interest recalculation, no interest on past due principal
balances,
+ // preClosureInterestCalculationStrategy= till preclose,
+ // interestRecalculationCompoundingMethod = none
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE)
+ String name51 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALC_DAILY_NO_CALC_ON_PAST_DUE_TILL_PRECLOSE
+ .getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalcDailyNoCalcOnPastDueTillPreclose
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name51)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+ .disallowInterestCalculationOnPastDue(true)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcNoCalcOnPastDueDailyTillPreClose
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalcDailyNoCalcOnPastDueTillPreclose)
+ .execute();
+ TestContext.INSTANCE.set(TestContextKey.temp,
+
responseLoanProductsRequestLP2AdvancedpaymentInterest36030InterestRecalcNoCalcOnPastDueDailyTillPreClose);
+
+ // LP2 with progressive loan schedule + horizontal + interest
recalculation daily EMI + 360/30
+ // + multi disbursement + no interest on past due principal balances,
+ //
(LP2_ADV_PAYMENT_ALLOC_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_EMI_360_30_MULTIDISBURSE)
+ String name52 =
DefaultLoanProduct.LP2_ADV_PAYMENT_ALLOC_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_EMI_360_30_MULTIDISBURSE
+ .getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvPaymentAllocationInterestRecalculationDailyNoCalcOnPastDueEmi36030MultiDisburse
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name52)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+ .disallowInterestCalculationOnPastDue(true)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")))
+ .multiDisburseLoan(true)//
+ .disallowExpectedDisbursements(true)//
+ .maxTrancheCount(10)//
+ .outstandingLoanBalance(10000.0);//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvPaymentAllocationInterestRecalculationDailyNoCalcOnPastDue36030MultiDisburse
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvPaymentAllocationInterestRecalculationDailyNoCalcOnPastDueEmi36030MultiDisburse)
+ .execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_PAYMENT_ALLOCATION_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_EMI_360_30_MULTIDISBURSE,
+
responseLoanProductsRequestLP2AdvPaymentAllocationInterestRecalculationDailyNoCalcOnPastDue36030MultiDisburse);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30 + multidisbursement + downpayment +
+ // interest recalculation
+ // 25%, auto enabled
+ //
(LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT)
+ String name53 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestRecalculationEmi36030MultiDisburseAutoDownPayment
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name53)//
+ .enableDownPayment(true)//
+ .disbursedAmountPercentageForDownPayment(new BigDecimal(25))//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+
.enableAutoRepaymentForDownPayment(true).paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")))//
+ .multiDisburseLoan(true)//
+ .disallowExpectedDisbursements(true)//
+ .maxTrancheCount(10)//
+ .outstandingLoanBalance(10000.0);//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestRecalculation36030MultiDisburseAutoDownPayment
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestRecalculationEmi36030MultiDisburseAutoDownPayment)
+ .execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestRecalculation36030MultiDisburseAutoDownPayment);
+
// LP2 + interest recalculation + zero-interest chargeOff behaviour +
progressive loan schedule + horizontal
//
(LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR)
- final String name51 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR
+ final String name54 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR
.getName();
final PostLoanProductsRequest
loanProductsRequestAdvInterestRecalculationZeroInterestChargeOffBehaviourProgressiveLoanSchedule
= loanProductsRequestFactory
.defaultLoanProductsRequestLP2InterestDailyRecalculation()//
- .name(name51)//
+ .name(name54)//
.paymentAllocation(List.of(//
createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT")))
.chargeOffBehaviour("ZERO_INTEREST");//
@@ -1109,11 +1210,11 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
// LP2 + zero-interest chargeOff behaviour + progressive loan schedule
+ horizontal
// (LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR)
- final String name52 =
DefaultLoanProduct.LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName();
+ final String name55 =
DefaultLoanProduct.LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName();
final PostLoanProductsRequest
loanProductsRequestAdvZeroInterestChargeOffBehaviourProgressiveLoanSchedule =
loanProductsRequestFactory
.defaultLoanProductsRequestLP2()//
- .name(name52)//
+ .name(name55)//
.enableDownPayment(false)//
.enableAutoRepaymentForDownPayment(null)//
.disbursedAmountPercentageForDownPayment(null)//
@@ -1133,7 +1234,7 @@ public class LoanProductGlobalInitializerStep implements
FineractGlobalInitializ
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_PRINCIPAL, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.DUE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PENALTY, //
-
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_FEE, //
+
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_FEE,
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_INTEREST, //
LoanProductPaymentAllocationRule.AllocationTypesEnum.IN_ADVANCE_PRINCIPAL), //
createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
@@ -1148,12 +1249,12 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
// LP2 with progressive loan schedule + horizontal + interest EMI +
360/30 + multidisbursement +
// accelerate-maturity chargeOff behaviour
//
(LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR)
- final String name53 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
+ final String name56 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
.getName();
- final PostLoanProductsRequest
loanProductsRequestAdvCustomInterestRecalculationAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsRequestFactory
+ final PostLoanProductsRequest
loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsRequestFactory
.defaultLoanProductsRequestLP2InterestDailyRecalculation()//
- .name(name53)//
+ .name(name56)//
.paymentAllocation(List.of(//
createPaymentAllocation("DEFAULT", "NEXT_INSTALLMENT",
LoanProductPaymentAllocationRule.AllocationTypesEnum.PAST_DUE_PENALTY, //
@@ -1172,19 +1273,280 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT"))) //
.chargeOffBehaviour("ACCELERATE_MATURITY");//
- final Response<PostLoanProductsResponse>
responseLoanProductsRequestAdvCustomInterestRecalculationAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsApi
- .createLoanProduct(
-
loanProductsRequestAdvCustomInterestRecalculationAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule)
- .execute();
+ final Response<PostLoanProductsResponse>
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsApi
+
.createLoanProduct(loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule).execute();
TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR,
-
responseLoanProductsRequestAdvCustomInterestRecalculationAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule);
+
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule);
+
+ // + interest recalculation, allowPartialPeriodInterestCalculation =
true
+ // interestRecalculationCompoundingMethod = none
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 2
+ // Frequency for Interest rate - Whole Year
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD)
+ String name57 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD
+ .getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyAllowPartialPeriod
= loanProductsRequestFactory//
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name57)//
+ .loanScheduleProcessingType("HORIZONTAL")//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+
.interestCalculationPeriodType(INTEREST_CALCULATION_PERIOD_TYPE_SAME_AS_REPAYMENT).preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(1)//
+ .recalculationRestFrequencyInterval(1)//
+ .repaymentEvery(1)//
+ .interestRatePerPeriod((double) 7.0)//
+
.interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_MONTH)//
+ .enableDownPayment(false)//
+ .interestRecalculationCompoundingMethod(0)//
+ .repaymentFrequencyType(REPAYMENT_FREQUENCY_TYPE_MONTHS)//
+ .allowPartialPeriodInterestCalcualtion(true)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyAllowPartialPeriod
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyAllowPartialPeriod)
+ .execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD,
+
responseLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyAllowPartialPeriod);
+
+ // LP2 + interest recalculation + zero-interest chargeOff behaviour +
progressive loan schedule + horizontal
+ // interest EMI + 360/30, preClosureInterestCalculationStrategy= till
preclose,
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF)
+ final String name58 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF.getName();
+ final PostLoanProductsRequest
loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyChargeOff
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2EmiWithChargeOff()//
+ .name(name58)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")))//
+ .chargeOffBehaviour("ZERO_INTEREST");//
+ final Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyChargeOff
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyChargeOff).execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF,
+
responseLoanProductsRequestLP2AdvancedPaymentInterestEmi36030InterestRecalculationDailyChargeOff);
+
+ // LP2 + NO interest recalculation + zero-interest chargeOff behaviour
+ progressive loan schedule + horizontal
+ // (LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF)
+ final String name59 =
DefaultLoanProduct.LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF.getName();
+ final PostLoanProductsRequest
loanProductsRequestLP2AdvancedPaymentNoInterestInterestRecalculationChargeOff =
loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2EmiWithChargeOff()//
+ .name(name59)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"))) //
+ .chargeOffBehaviour("ZERO_INTEREST");//
+ final Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedPaymentNoInterestInterestRecalculationChargeOff
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedPaymentNoInterestInterestRecalculationChargeOff).execute();
+
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF,
+
responseLoanProductsRequestLP2AdvancedPaymentNoInterestInterestRecalculationChargeOff);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
actual/actual + accrual activity posting +
+ // down payment
+ // enableAccrualActivityPosting
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_AUTO_DOWNPAYMENT_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY)
+ String name60 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_AUTO_DOWNPAYMENT_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestAutoDownpaymentEmiActualActualAccrualActivity
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name60)//
+ .enableDownPayment(true)//
+ .disbursedAmountPercentageForDownPayment(new BigDecimal(25))//
+ .enableAutoRepaymentForDownPayment(true)//
+ .enableAccrualActivityPosting(true)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestAutoDownpaymentEmiActualActualAccrualActivity
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestAutoDownpaymentEmiActualActualAccrualActivity).execute();
+
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestAutoDownpaymentEmiActualActualAccrualActivity);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30
+ // + interest recalculation, preClosureInterestCalculationStrategy=
till preclose,
+ // interestRecalculationCompoundingMethod = none
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ // AccrualActivityPostingEnabled = true
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING)
+ String name61 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING
+ .getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyAccrualActivityPosting
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name61)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+
.enableAccrualActivityPosting(true).paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseloanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyAccrualActivityPosting
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyAccrualActivityPosting)
+ .execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING,
+
responseloanProductsRequestLP2AdvancedpaymentInterestEmi36030InterestRecalcDailyAccrualActivityPosting);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/Actual
+ // (LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_ACTUAL)
+ String name62 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_ACTUAL.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterest360Actual =
loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name62)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.ACTUAL.value)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestEmi360Actual =
loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterest360Actual).execute();
+
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_ACTUAL,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestEmi360Actual);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30
+ // Chargeback: Interest, Fee, Principal
+ // + interest recalculation DISABLED
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL)
+ String name63 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestFeePrincipal
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name63)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .creditAllocation(List.of(//
+ createCreditAllocation("CHARGEBACK",
List.of("INTEREST", "FEE", "PRINCIPAL", "PENALTY"))//
+ ))//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestFeePrincipal
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestFeePrincipal).execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestFeePrincipal);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30
+ // Chargeback: Principal, Interest, Fee
+ // + interest recalculation DISABLED
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE)
+ String name64 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackPrincipalInterestFee
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name64)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .creditAllocation(List.of(//
+ createCreditAllocation("CHARGEBACK",
List.of("PRINCIPAL", "INTEREST", "FEE", "PENALTY"))//
+ ))//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackPrincipalInterestFee
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackPrincipalInterestFee).execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackPrincipalInterestFee);
// LP2
+
// with
+
// progressive
+
// loan
+
// schedule
+
// +
+
// horizontal
+
// +
+
// interest
+
// EMI
+
// +
+
// 360/30
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
360/30
+ // Chargeback: Interest, Penalty, Fee, Principal
+ // + interest recalculation DISABLED
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL)
+ String name65 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestPenaltyFeePrincipal
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name65)//
+ .daysInYearType(DaysInYearType.DAYS360.value)//
+ .daysInMonthType(DaysInMonthType.DAYS30.value)//
+ .creditAllocation(List.of(//
+ createCreditAllocation("CHARGEBACK",
List.of("INTEREST", "PENALTY", "FEE", "PRINCIPAL"))//
+ ))//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestPenaltyFeePrincipal
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestPenaltyFeePrincipal)
+ .execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestDailyEmi36030ChargebackInterestPenaltyFeePrincipal);
+
+ // LP2 with progressive loan schedule + horizontal + interest EMI +
actual/actual
+ // + interest recalculation, preClosureInterestCalculationStrategy=
till preclose,
+ // Frequency for recalculate Outstanding Principal: Daily, Frequency
Interval for recalculation: 1
+ //
(LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY)
+ String name66 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY.getName();
+ PostLoanProductsRequest
loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRecalculationDaily
= loanProductsRequestFactory
+ .defaultLoanProductsRequestLP2Emi()//
+ .name(name66)//
+ .maxPrincipal(1000000.0)//
+ .isInterestRecalculationEnabled(true)//
+ .preClosureInterestCalculationStrategy(1)//
+ .rescheduleStrategyMethod(4)//
+ .interestRecalculationCompoundingMethod(0)//
+ .recalculationRestFrequencyType(2)//
+ .recalculationRestFrequencyInterval(1)//
+ .paymentAllocation(List.of(//
+ createPaymentAllocation("DEFAULT",
"NEXT_INSTALLMENT"), //
+ createPaymentAllocation("GOODWILL_CREDIT",
"LAST_INSTALLMENT"), //
+ createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
+ createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")));//
+ Response<PostLoanProductsResponse>
responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRecalculationDaily
= loanProductsApi
+
.createLoanProduct(loanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRecalculationDaily).execute();
+ TestContext.INSTANCE.set(
+
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY,
+
responseLoanProductsRequestLP2AdvancedpaymentInterestEmiActualActualInterestRecalculationDaily);
// LP2 with progressive loan schedule + horizontal + interest EMI +
360/30 + accrual activity
- String name54 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY.getName();
+ String name67 =
DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY.getName();
PostLoanProductsRequest
loanProductsRequestLP2AdvancedPaymentInterestEmi36030AccrualActivity =
loanProductsRequestFactory
.defaultLoanProductsRequestLP2Emi()//
- .name(name54)//
+ .name(name67)//
.enableAccrualActivityPosting(true)//
.daysInYearType(DaysInYearType.DAYS360.value)//
.daysInMonthType(DaysInMonthType.DAYS30.value)//
@@ -1207,11 +1569,11 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
// LP2 with progressive loan schedule + horizontal +
accelerate-maturity chargeOff behaviour
// (LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR)
- final String name55 =
DefaultLoanProduct.LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR.getName();
+ final String name68 =
DefaultLoanProduct.LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR.getName();
- final PostLoanProductsRequest
loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsRequestFactory
+ final PostLoanProductsRequest
loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule2
= loanProductsRequestFactory
.defaultLoanProductsRequestLP2()//
- .name(name55)//
+ .name(name68)//
.enableDownPayment(false)//
.enableAutoRepaymentForDownPayment(null)//
.disbursedAmountPercentageForDownPayment(null)//
@@ -1238,16 +1600,16 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
createPaymentAllocation("MERCHANT_ISSUED_REFUND",
"REAMORTIZATION"), //
createPaymentAllocation("PAYOUT_REFUND",
"NEXT_INSTALLMENT")))//
.chargeOffBehaviour("ACCELERATE_MATURITY");//
- final Response<PostLoanProductsResponse>
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule
= loanProductsApi
-
.createLoanProduct(loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule).execute();
+ final Response<PostLoanProductsResponse>
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule2
= loanProductsApi
+
.createLoanProduct(loanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule2).execute();
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR,
-
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule);
+
responseLoanProductsRequestAdvCustomAccelerateMaturityChargeOffBehaviourProgressiveLoanSchedule2);
// LP2 with disabled interest recalculation + chargeback
allocation(INTEREST, PENALTY, FEE, PRINCIPAL)
// (LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST)
- String name56 =
DefaultLoanProduct.LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST.getName();
+ String name69 =
DefaultLoanProduct.LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST.getName();
PostLoanProductsRequest loanProductsRequestChargebackAllocation =
loanProductsRequestFactory.defaultLoanProductsRequestLP2Emi()//
- .name(name56)//
+ .name(name69)//
.daysInYearType(DaysInYearType.DAYS360.value)//
.daysInMonthType(DaysInMonthType.DAYS30.value)//
.creditAllocation(List.of(//
@@ -1265,10 +1627,10 @@ public class LoanProductGlobalInitializerStep
implements FineractGlobalInitializ
// LP2 with disabled interest recalculation + chargeback
allocation(PRINCIPAL, INTEREST, PENALTY, FEE)
//
(LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_PRINCIPAL_FIRST)
- String name57 =
DefaultLoanProduct.LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_PRINCIPAL_FIRST.getName();
+ String name70 =
DefaultLoanProduct.LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_PRINCIPAL_FIRST.getName();
PostLoanProductsRequest
loanProductsRequestChargebackAllocationPrincipalFirst =
loanProductsRequestFactory
.defaultLoanProductsRequestLP2Emi()//
- .name(name57)//
+ .name(name70)//
.daysInYearType(DaysInYearType.DAYS360.value)//
.daysInMonthType(DaysInMonthType.DAYS30.value)//
.creditAllocation(List.of(//
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
index 6be5bd642..f14fd300e 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/EventCheckHelper.java
@@ -251,6 +251,14 @@ public class EventCheckHelper {
return targetTransaction;
}
+ public GetLoansLoanIdTransactions findNthTransaction(String nthItemStr,
String transactionType, String transactionDate, long loanId)
+ throws IOException {
+ List<GetLoansLoanIdTransactions> transactions =
loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute().body()
+ .getTransactions();
+ GetLoansLoanIdTransactions targetTransaction =
getNthTransactionType(nthItemStr, transactionType, transactionDate,
transactions);
+ return targetTransaction;
+ }
+
public void
checkTransactionWithLoanTransactionAdjustmentBizEvent(GetLoansLoanIdTransactions
transaction) {
EventAssertion.EventAssertionBuilder<LoanTransactionAdjustmentDataV1>
eventAssertionBuilder = eventAssertion
.assertEvent(LoanAdjustTransactionBusinessEvent.class,
transaction.getId());
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanChargeAdjustmentPostBusinessEvent.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanChargeAdjustmentPostBusinessEvent.java
new file mode 100644
index 000000000..57df12c00
--- /dev/null
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/messaging/event/loan/transaction/LoanChargeAdjustmentPostBusinessEvent.java
@@ -0,0 +1,27 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.fineract.test.messaging.event.loan.transaction;
+
+public class LoanChargeAdjustmentPostBusinessEvent extends
AbstractLoanTransactionEvent {
+
+ @Override
+ public String getEventName() {
+ return "LoanChargeAdjustmentPostBusinessEvent";
+ }
+}
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java
index e0db1f459..f8baa6b60 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/common/SchedulerStepDef.java
@@ -52,6 +52,16 @@ public class SchedulerStepDef extends AbstractStepDef {
jobService.executeAndWait(DefaultJob.LOAN_DELINQUENCY_CLASSIFICATION);
}
+ @When("Admin runs the Add Accrual Transactions For Loans With Income
Posted As Transactions job")
+ public void
runAddAccrualTransactionsForLoansWithIncomePostedAsTransactions() {
+
jobService.executeAndWait(DefaultJob.ADD_ACCRUAL_TRANSACTIONS_FOR_LOANS_WITH_INCOME_POSTED_AS_TRANSACTIONS);
+ }
+
+ @When("Admin runs the Recalculate Interest for Loans job")
+ public void runRecalculateInterestForLoans() {
+ jobService.executeAndWait(DefaultJob.RECALCULATE_INTEREST_FOR_LOANS);
+ }
+
@When("Admin runs COB job")
public void runCOB() {
jobService.executeAndWait(DefaultJob.LOAN_COB);
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanInterestPauseStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanInterestPauseStepDef.java
index 86ee0ea1a..63aeafffa 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanInterestPauseStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanInterestPauseStepDef.java
@@ -35,7 +35,7 @@ public class LoanInterestPauseStepDef extends AbstractStepDef
{
@Autowired
private LoanInterestPauseApi loanInterestPauseApi;
- @And("Create interest pause period with start date {string} and end date
{string}")
+ @And("Create an interest pause period with start date {string} and end
date {string}")
public void createInterestPause(final String startDate, final String
endDate) throws IOException {
final Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
assert loanResponse.body() != null;
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
index 7e53d85d3..e0e0e9370 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanRepaymentStepDef.java
@@ -21,6 +21,7 @@ package org.apache.fineract.test.stepdef.loan;
import static
org.apache.fineract.test.data.paymenttype.DefaultPaymentType.AUTOPAY;
import static org.assertj.core.api.Assertions.assertThat;
+import com.google.gson.Gson;
import io.cucumber.java.en.And;
import io.cucumber.java.en.Then;
import io.cucumber.java.en.When;
@@ -51,6 +52,7 @@ import org.apache.fineract.client.models.PostUsersResponse;
import org.apache.fineract.client.services.LoanTransactionsApi;
import org.apache.fineract.client.services.LoansApi;
import org.apache.fineract.client.services.UsersApi;
+import org.apache.fineract.client.util.JSON;
import org.apache.fineract.test.data.TransactionType;
import org.apache.fineract.test.data.paymenttype.DefaultPaymentType;
import org.apache.fineract.test.data.paymenttype.PaymentTypeResolver;
@@ -79,6 +81,8 @@ public class LoanRepaymentStepDef extends AbstractStepDef {
public static final String DEFAULT_REPAYMENT_TYPE = "AUTOPAY";
private static final String PWD_USER_WITH_ROLE = "1234567890Aa!";
+ private static final Gson GSON = new JSON().getGson();
+
@Autowired
private LoanTransactionsApi loanTransactionsApi;
@@ -446,6 +450,40 @@ public class LoanRepaymentStepDef extends AbstractStepDef {
eventCheckHelper.loanBalanceChangedEventCheck(loanId);
}
+ @Then("Customer is forbidden to undo {string}th {string} transaction made
on {string}")
+ public void makeTransactionUndoForbidden(String nthItemStr, String
transactionType, String transactionDate) throws IOException {
+ eventStore.reset();
+ Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanResponse.body().getLoanId();
+ GetLoansLoanIdTransactions targetTransaction =
eventCheckHelper.findNthTransaction(nthItemStr, transactionType,
transactionDate,
+ loanId);
+
+ PostLoansLoanIdTransactionsTransactionIdRequest transactionUndoRequest
= LoanRequestFactory.defaultTransactionUndoRequest()
+ .transactionDate(transactionDate);
+
+ Response<PostLoansLoanIdTransactionsResponse> transactionUndoResponse
= loanTransactionsApi
+ .adjustLoanTransaction(loanId, targetTransaction.getId(),
transactionUndoRequest, "").execute();
+
+ String string = transactionUndoResponse.errorBody().string();
+ ErrorResponse errorResponse = GSON.fromJson(string,
ErrorResponse.class);
+ Integer httpStatusCodeActual = errorResponse.getHttpStatusCode();
+ String developerMessageActual =
errorResponse.getErrors().get(0).getDeveloperMessage();
+
+ Integer httpStatusCodeExpected = 403;
+ String developerMessageExpected = String.format("Interest refund
transaction: %s cannot be reversed or adjusted directly",
+ targetTransaction.getId());
+
+ assertThat(httpStatusCodeActual)
+
.as(ErrorMessageHelper.wrongErrorCodeInFailedChargeAdjustment(httpStatusCodeActual,
httpStatusCodeExpected))
+ .isEqualTo(httpStatusCodeExpected);
+ assertThat(developerMessageActual)
+
.as(ErrorMessageHelper.wrongErrorMessageInFailedChargeAdjustment(developerMessageActual,
developerMessageExpected))
+ .isEqualTo(developerMessageExpected);
+
+ log.debug("Error code: {}", httpStatusCodeActual);
+ log.debug("Error message: {}", developerMessageActual);
+ }
+
@When("Customer undo {string}th {string} transaction made on {string} with
linked {string} transaction")
public void checkNthTransactionType(String nthItemStr, String
transactionType, String transactionDate, String linkedTransactionType)
throws IOException {
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
index 6e3177472..1d1185cc8 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanStepDef.java
@@ -22,6 +22,7 @@ import static
org.apache.fineract.test.data.TransactionProcessingStrategyCode.AD
import static
org.apache.fineract.test.data.loanproduct.DefaultLoanProduct.LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR;
import static
org.apache.fineract.test.data.loanproduct.DefaultLoanProduct.LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR;
import static
org.apache.fineract.test.data.loanproduct.DefaultLoanProduct.LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR;
+import static
org.apache.fineract.test.factory.LoanProductsRequestFactory.CHARGE_OFF_REASONS;
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
import static org.junit.Assert.assertFalse;
@@ -55,6 +56,7 @@ import
org.apache.fineract.avro.loan.v1.LoanChargePaidByDataV1;
import org.apache.fineract.avro.loan.v1.LoanStatusEnumDataV1;
import org.apache.fineract.avro.loan.v1.LoanTransactionDataV1;
import org.apache.fineract.client.models.AdvancedPaymentData;
+import org.apache.fineract.client.models.CommandProcessingResult;
import org.apache.fineract.client.models.DeleteLoansLoanIdResponse;
import org.apache.fineract.client.models.GetLoanProductsChargeOffReasonOptions;
import org.apache.fineract.client.models.GetLoanProductsProductIdResponse;
@@ -70,6 +72,7 @@ import
org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdTimeline;
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
import
org.apache.fineract.client.models.GetLoansLoanIdTransactionsTransactionIdResponse;
+import org.apache.fineract.client.models.InterestPauseRequestDto;
import org.apache.fineract.client.models.IsCatchUpRunningResponse;
import org.apache.fineract.client.models.PaymentAllocationOrder;
import org.apache.fineract.client.models.PostClientsResponse;
@@ -85,6 +88,7 @@ import
org.apache.fineract.client.models.PutLoanProductsProductIdResponse;
import org.apache.fineract.client.models.PutLoansLoanIdRequest;
import org.apache.fineract.client.models.PutLoansLoanIdResponse;
import org.apache.fineract.client.services.LoanCobCatchUpApi;
+import org.apache.fineract.client.services.LoanInterestPauseApi;
import org.apache.fineract.client.services.LoanProductsApi;
import org.apache.fineract.client.services.LoanTransactionsApi;
import org.apache.fineract.client.services.LoansApi;
@@ -98,11 +102,15 @@ import org.apache.fineract.test.data.LoanTermFrequencyType;
import org.apache.fineract.test.data.RepaymentFrequencyType;
import org.apache.fineract.test.data.TransactionProcessingStrategyCode;
import org.apache.fineract.test.data.TransactionType;
+import org.apache.fineract.test.data.codevalue.CodeValue;
+import org.apache.fineract.test.data.codevalue.CodeValueResolver;
+import org.apache.fineract.test.data.codevalue.DefaultCodeValue;
import org.apache.fineract.test.data.loanproduct.DefaultLoanProduct;
import org.apache.fineract.test.data.loanproduct.LoanProductResolver;
import org.apache.fineract.test.data.paymenttype.DefaultPaymentType;
import org.apache.fineract.test.data.paymenttype.PaymentTypeResolver;
import org.apache.fineract.test.factory.LoanRequestFactory;
+import org.apache.fineract.test.helper.CodeHelper;
import org.apache.fineract.test.helper.ErrorHelper;
import org.apache.fineract.test.helper.ErrorMessageHelper;
import org.apache.fineract.test.helper.ErrorResponse;
@@ -113,6 +121,7 @@ import
org.apache.fineract.test.messaging.event.EventCheckHelper;
import
org.apache.fineract.test.messaging.event.loan.LoanRescheduledDueAdjustScheduleEvent;
import org.apache.fineract.test.messaging.event.loan.LoanStatusChangedEvent;
import
org.apache.fineract.test.messaging.event.loan.transaction.LoanAccrualTransactionCreatedBusinessEvent;
+import
org.apache.fineract.test.messaging.event.loan.transaction.LoanChargeAdjustmentPostBusinessEvent;
import
org.apache.fineract.test.messaging.event.loan.transaction.LoanChargeOffEvent;
import
org.apache.fineract.test.messaging.event.loan.transaction.LoanChargeOffUndoEvent;
import
org.apache.fineract.test.messaging.event.loan.transaction.LoanTransactionAccrualActivityPostEvent;
@@ -170,6 +179,15 @@ public class LoanStepDef extends AbstractStepDef {
@Autowired
private EventStore eventStore;
+ @Autowired
+ private CodeValueResolver codeValueResolver;
+
+ @Autowired
+ private CodeHelper codeHelper;
+
+ @Autowired
+ private LoanInterestPauseApi loanInterestPauseApi;
+
@When("Admin creates a new Loan")
public void createLoan() throws IOException {
Response<PostClientsResponse> clientResponse =
testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE);
@@ -1405,6 +1423,60 @@ public class LoanStepDef extends AbstractStepDef {
.isEqualTo(loanId).extractingData(LoanTransactionDataV1::getId).isEqualTo(chargeOffResponse.body().getResourceId());
}
+ @Then("Backdated charge-off on a date {string} is forbidden")
+ public void chargeOffBackdatedForbidden(String transactionDate) throws
IOException {
+ Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanResponse.body().getLoanId();
+
+ PostLoansLoanIdTransactionsRequest chargeOffRequest =
LoanRequestFactory.defaultChargeOffRequest().transactionDate(transactionDate)
+ .dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE);
+
+ Response<PostLoansLoanIdTransactionsResponse> chargeOffResponse =
loanTransactionsApi
+ .executeLoanTransaction(loanId, chargeOffRequest,
"charge-off").execute();
+ testContext().set(TestContextKey.LOAN_CHARGE_OFF_RESPONSE,
chargeOffResponse);
+
+ assertThat(chargeOffResponse.isSuccessful()).isFalse();
+
+ String string = chargeOffResponse.errorBody().string();
+ ErrorResponse errorResponse = GSON.fromJson(string,
ErrorResponse.class);
+
+ Integer httpStatusCodeActual = errorResponse.getHttpStatusCode();
+ String developerMessageActual =
errorResponse.getErrors().get(0).getDeveloperMessage();
+
+ Integer httpStatusCodeExpected = 403;
+ String developerMessageExpected = String.format(
+ "Loan: %s charge-off cannot be executed. Loan has monetary
activity after the charge-off transaction date!", loanId);
+
+ assertThat(httpStatusCodeActual)
+
.as(ErrorMessageHelper.wrongErrorCodeInFailedChargeAdjustment(httpStatusCodeActual,
httpStatusCodeExpected))
+ .isEqualTo(httpStatusCodeExpected);
+ assertThat(developerMessageActual)
+
.as(ErrorMessageHelper.wrongErrorMessageInFailedChargeAdjustment(developerMessageActual,
developerMessageExpected))
+ .isEqualTo(developerMessageExpected);
+ }
+
+ @And("Admin does charge-off the loan with reason {string} on {string}")
+ public void chargeOffLoan(String chargeOffReason, String transactionDate)
throws IOException {
+ Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanResponse.body().getLoanId();
+
+ final CodeValue chargeOffReasonCodeValue =
DefaultCodeValue.valueOf(chargeOffReason);
+ Long chargeOffReasonCodeId =
codeHelper.retrieveCodeByName(CHARGE_OFF_REASONS).getId();
+ long chargeOffReasonId =
codeValueResolver.resolve(chargeOffReasonCodeId, chargeOffReasonCodeValue);
+
+ PostLoansLoanIdTransactionsRequest chargeOffRequest =
LoanRequestFactory.defaultChargeOffRequest()
+
.chargeOffReasonId(chargeOffReasonId).transactionDate(transactionDate).dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE);
+
+ Response<PostLoansLoanIdTransactionsResponse> chargeOffResponse =
loanTransactionsApi
+ .executeLoanTransaction(loanId, chargeOffRequest,
"charge-off").execute();
+ testContext().set(TestContextKey.LOAN_CHARGE_OFF_RESPONSE,
chargeOffResponse);
+ ErrorHelper.checkSuccessfulApiCall(chargeOffResponse);
+
+ Long transactionId = chargeOffResponse.body().getResourceId();
+ eventAssertion.assertEvent(LoanChargeOffEvent.class,
transactionId).extractingData(LoanTransactionDataV1::getLoanId)
+
.isEqualTo(loanId).extractingData(LoanTransactionDataV1::getId).isEqualTo(chargeOffResponse.body().getResourceId());
+ }
+
@And("Admin tries to charge-off the loan on {string} but fails due to
monetary activity after the charge-off date")
public void chargeOffLoanWithError(final String transactionDate) throws
IOException {
final Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -1573,6 +1645,23 @@ public class LoanStepDef extends AbstractStepDef {
log.debug("Error message: {}", developerMessage);
}
+ @Then("Admin fails to disburse the loan on {string} with {string} EUR
transaction amount because of charge-off that was performed for the loan")
+ public void disburseChargedOffLoanFailure(String actualDisbursementDate,
String transactionAmount) throws IOException {
+ Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanResponse.body().getLoanId();
+ PostLoansLoanIdRequest disburseRequest =
LoanRequestFactory.defaultLoanDisburseRequest()
+
.actualDisbursementDate(actualDisbursementDate).transactionAmount(new
BigDecimal(transactionAmount));
+
+ Response<PostLoansLoanIdResponse> loanDisburseResponse =
loansApi.stateTransitions(loanId, disburseRequest, "disburse").execute();
+ testContext().set(TestContextKey.LOAN_DISBURSE_RESPONSE,
loanDisburseResponse);
+ ErrorResponse errorDetails = ErrorResponse.from(loanDisburseResponse);
+ String developerMessage =
errorDetails.getSingleError().getDeveloperMessage();
+
+
assertThat(errorDetails.getHttpStatusCode()).as(ErrorMessageHelper.dateFailureErrorCodeMsg()).isEqualTo(403);
+
assertThat(developerMessage).matches(ErrorMessageHelper.disburseChargedOffLoanFailure());
+ log.debug("Error message: {}", developerMessage);
+ }
+
@Then("Loan has {double} outstanding amount")
public void loanOutstanding(double totalOutstandingExpected) throws
IOException {
Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -1795,6 +1884,57 @@ public class LoanStepDef extends AbstractStepDef {
assertThat(isReverted).as(ErrorMessageHelper.transactionIsNotReversedError(isReverted,
false)).isEqualTo(false);
}
+ @Then("In Loan Transactions the {string}th Transaction with type={string}
and date {string} has non-null external-id")
+ public void loanTransactionsNthTransactionHasNonNullExternalId(String
nthTransactionStr, String transactionType, String transactionDate)
+ throws IOException {
+ Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanCreateResponse.body().getLoanId();
+
+ Response<GetLoansLoanIdResponse> loanDetailsResponse =
loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
+ ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
+
+ List<GetLoansLoanIdTransactions> transactions =
loanDetailsResponse.body().getTransactions();
+ int nthItem = Integer.parseInt(nthTransactionStr) - 1;
+ GetLoansLoanIdTransactions targetTransaction = transactions//
+ .stream()//
+ .filter(t ->
transactionDate.equals(FORMATTER.format(t.getDate())) &&
transactionType.equals(t.getType().getValue()))//
+ .toList().get(nthItem);//
+
+
assertThat(targetTransaction.getExternalId()).as(ErrorMessageHelper.transactionHasNullResourceValue(transactionType,
"external-id"))
+ .isNotNull();
+ testContext().set(TestContextKey.LOAN_TRANSACTION_RESPONSE,
targetTransaction);
+ }
+
+ @Then("In Loan Transactions all transactions have non-null external-id")
+ public void loanTransactionsHaveNonNullExternalId() throws IOException {
+ Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanCreateResponse.body().getLoanId();
+
+ Response<GetLoansLoanIdResponse> loanDetailsResponse =
loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
+ ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
+
+ List<GetLoansLoanIdTransactions> transactions =
loanDetailsResponse.body().getTransactions();
+
+ assertThat(transactions.stream().allMatch(transaction ->
transaction.getExternalId() != null))
+ .as(ErrorMessageHelper.transactionHasNullResourceValue("",
"external-id")).isTrue();
+ }
+
+ @Then("Check required transaction for non-null eternal-id")
+ public void loanTransactionHasNonNullExternalId() throws IOException {
+ Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanCreateResponse.body().getLoanId();
+
+ GetLoansLoanIdTransactions targetTransaction =
testContext().get(TestContextKey.LOAN_TRANSACTION_RESPONSE);
+ Long targetTransactionId = targetTransaction.getId();
+
+ Response<GetLoansLoanIdTransactionsTransactionIdResponse>
transactionResponse = loanTransactionsApi
+ .retrieveTransaction(loanId, targetTransactionId,
"").execute();
+
+ GetLoansLoanIdTransactionsTransactionIdResponse transaction =
transactionResponse.body();
+ assertThat(transaction.getExternalId())
+
.as(ErrorMessageHelper.transactionHasNullResourceValue(transaction.getType().getCode(),
"external-id")).isNotNull();
+ }
+
@Then("Loan Charges tab has a given charge with the following data:")
public void loanChargesGivenChargeDataCheck(DataTable table) throws
IOException {
Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -2186,6 +2326,37 @@ public class LoanStepDef extends AbstractStepDef {
eventAssertion.assertEventRaised(LoanAccrualTransactionCreatedBusinessEvent.class,
accrualTransactionId);
}
+ @Then("LoanChargeAdjustmentPostBusinessEvent is raised on {string}")
+ public void checkLoanChargeAdjustmentPostBusinessEvent(String date) throws
IOException {
+ Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanCreateResponse.body().getLoanId();
+
+ Response<GetLoansLoanIdResponse> loanDetailsResponse =
loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
+ ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
+
+ List<GetLoansLoanIdTransactions> transactions =
loanDetailsResponse.body().getTransactions();
+
+ GetLoansLoanIdTransactions loadTransaction = transactions.stream()
+ .filter(t -> date.equals(FORMATTER.format(t.getDate())) &&
"Charge Adjustment".equals(t.getType().getValue())).findFirst()
+ .orElseThrow(() -> new IllegalStateException(String.format("No
Charge Adjustment transaction found on %s", date)));
+
+
eventAssertion.assertEventRaised(LoanChargeAdjustmentPostBusinessEvent.class,
loadTransaction.getId());
+ }
+
+ @Then("LoanAccrualTransactionCreatedBusinessEvent is not raised on
{string}")
+ public void checkLoanAccrualTransactionNotCreatedBusinessEvent(String
date) throws IOException {
+ Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanCreateResponse.body().getLoanId();
+
+ Response<GetLoansLoanIdResponse> loanDetailsResponse =
loansApi.retrieveLoan(loanId, false, "transactions", "", "").execute();
+ ErrorHelper.checkSuccessfulApiCall(loanDetailsResponse);
+
+ List<GetLoansLoanIdTransactions> transactions =
loanDetailsResponse.body().getTransactions();
+
+ assertThat(transactions).as("Unexpected Accrual activity transaction
found on %s", date)
+ .noneMatch(t -> date.equals(FORMATTER.format(t.getDate())) &&
"Accrual Activity".equals(t.getType().getValue()));
+ }
+
@Then("LoanTransactionAccrualActivityPostBusinessEvent is raised on
{string}")
public void checkLoanTransactionAccrualActivityPostBusinessEvent(String
date) throws IOException {
Response<PostLoansResponse> loanCreateResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -2475,6 +2646,18 @@ public class LoanStepDef extends AbstractStepDef {
.isEqualTo(expectedAmountParsed);
}
+ @Then("Create interest pause period with start date {string} and end date
{string}")
+ public void interestPauseCreate(final String startDate, final String
endDate) throws IOException {
+ Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
+ long loanId = loanResponse.body().getLoanId();
+
+ final InterestPauseRequestDto interestPauseRequest =
LoanRequestFactory.defaultInterestPauseRequest().startDate(startDate)
+ .endDate(endDate);
+ final Response<CommandProcessingResult> interestPauseResponse =
loanInterestPauseApi
+ .createInterestPause(loanId, interestPauseRequest).execute();
+ ErrorHelper.checkSuccessfulApiCall(interestPauseResponse);
+ }
+
@Then("LoanDetails has fixedLength field with int value: {int}")
public void checkLoanDetailsFieldAndValueInt(int fieldValue) throws
IOException, NoSuchMethodException {
Response<PostLoansResponse> loanResponse =
testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -2790,13 +2973,43 @@ public class LoanStepDef extends AbstractStepDef {
@When("Admin creates a new zero charge-off Loan with interest
recalculation and date: {string}")
public void
createLoanWithInterestRecalculationAndZeroChargeOffBehaviour(final String date)
throws IOException {
- createLoanWithLoanBehaviour(date, true, DefaultLoanProduct
-
.valueOf(LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName()));
+ createLoanWithZeroChargeOffBehaviour(date, true);
}
@When("Admin creates a new zero charge-off Loan without interest
recalculation and with date: {string}")
public void
createLoanWithoutInterestRecalculationAndZeroChargeOffBehaviour(final String
date) throws IOException {
- createLoanWithLoanBehaviour(date, false,
DefaultLoanProduct.valueOf(LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName()));
+ createLoanWithZeroChargeOffBehaviour(date, false);
+ }
+
+ private void createLoanWithZeroChargeOffBehaviour(final String date, final
boolean isInterestRecalculation) throws IOException {
+ final Response<PostClientsResponse> clientResponse =
testContext().get(TestContextKey.CLIENT_CREATE_RESPONSE);
+ final Long clientId = clientResponse.body().getClientId();
+
+ final DefaultLoanProduct product = isInterestRecalculation
+ ? DefaultLoanProduct
+
.valueOf(LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName())
+ :
DefaultLoanProduct.valueOf(LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR.getName());
+
+ final Long loanProductId = loanProductResolver.resolve(product);
+
+ final PostLoansRequest loansRequest =
loanRequestFactory.defaultLoansRequest(clientId).productId(loanProductId)
+ .principal(new
BigDecimal(100)).numberOfRepayments(6).submittedOnDate(date).expectedDisbursementDate(date)
+ .loanTermFrequency(6)//
+ .loanTermFrequencyType(LoanTermFrequencyType.MONTHS.value)//
+ .repaymentEvery(1)//
+ .repaymentFrequencyType(RepaymentFrequencyType.MONTHS.value)//
+ .interestRateFrequencyType(3)//
+ .interestRatePerPeriod(new BigDecimal(7))//
+ .interestType(InterestType.DECLINING_BALANCE.value)//
+ .interestCalculationPeriodType(isInterestRecalculation ?
InterestCalculationPeriodTime.DAILY.value
+ :
InterestCalculationPeriodTime.SAME_AS_REPAYMENT_PERIOD.value)//
+
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.value);
+
+ final Response<PostLoansResponse> response =
loansApi.calculateLoanScheduleOrSubmitLoanApplication(loansRequest,
"").execute();
+ testContext().set(TestContextKey.LOAN_CREATE_RESPONSE, response);
+ ErrorHelper.checkSuccessfulApiCall(response);
+
+ eventCheckHelper.createLoanEventCheck(response);
}
@When("Admin creates a new accelerate maturity charge-off Loan without
interest recalculation and with date: {string}")
diff --git
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
index 824556eef..d7f5c0872 100644
---
a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
+++
b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/support/TestContextKey.java
@@ -85,11 +85,12 @@ public abstract class TestContextKey {
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_ADV_PMT_ALLOC_FIXED_LENGTH
= "loanProductCreateResponseLP2DownPaymentProgressiveLoanScheduleFixedLength";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_DOWNPAYMENT_INTEREST_FLAT_ADV_PMT_ALLOC
=
"loanProductCreateResponseLP2DownPaymentInterestFlatAdvancedPaymentAllocation";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT
=
"loanProductCreateResponseLP2AdvancedPaymentInterestRecalculationDailyEmi36030MultiDisburseDownPayment";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE_AUTO_DOWNPAYMENT
=
"loanProductCreateResponseLP2AdvancedPaymentInterestRecalculationDailyEmi36030MultiDisburseEnabledDownPayment";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL
= "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActual";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_ACCRUAL_ACTIVITY
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualAccrualActivity";
- public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY
= "loanProductCreateResponseLP2AdvancedPaymentInterestEmi36030AccrualActivity";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30 =
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreClose";
+ public static final String temp =
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyNoCalcOnPastDueTillPreClose";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_LAST_INSTALLMENT
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreCloseLastInstallment";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_PMT_ALLOC_1
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreClosePmtAlloc1";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_PRECLOSE
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillPreClose";
@@ -97,18 +98,31 @@ public abstract class TestContextKey {
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_SAME_AS_REP_TILL_REST_FREQUENCY_DATE
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillRestFrequencyDate";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_FULL
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRefundFull";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030MultiDisburse";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_PAYMENT_ALLOCATION_INTEREST_RECALCULATION_DAILY_NO_CALC_ON_PAST_DUE_EMI_360_30_MULTIDISBURSE
=
"loanProductCreateResponseLP2AdvancedPaymentAllocationInterestRecalculationDailyNoCalcOnPastDueEmi36030MultiDisburse";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADVANCED_CUSTOM_PAYMENT_ALLOCATION_INTEREST_RECALCULATION_DAILY_EMI_360_30_MULTIDISBURSE
=
"loanProductCreateResponseLP2AdvancedCustomPaymentInterestRecalculationDailyEmi36030MultiDisburse";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_MULTIDISBURSE_DOWNPAYMENT
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030MultiDisburseDownPayment";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_365_ACTUAL
= "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi365Actual";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_ACTUAL
= "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi360Actual";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_DOWNPAYMENT
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030DownPayment";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRefund";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP1_ADVANCED_PAYMENT_ALLOCATION_PROGRESSIVE_LOAN_SCHEDULE_HORIZONTAL
= "loanProductCreateResponseLP1ProgressiveLoanScheduleHorizontal";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_WHOLE_TERM
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationSameAsRepTillPreCloseWholeTerm";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_REFUND_INTEREST_RECALCULATION
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRefundFInterestRecalculation";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationZeroInterestChargeOffBehaviour";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ZERO_INTEREST_CHARGE_OFF
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationZeroInterestChargeOff";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF_BEHAVIOUR
= "loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOffBehaviour";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ZERO_INTEREST_CHARGE_OFF =
"loanProductCreateResponseLP2AdvancedPaymentZeroInterestChargeOff";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ALLOW_PARTIAL_PERIOD
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAllowPartialPeriod";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_ACCRUAL_ACTIVITY_POSTING
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyAccrualActivityPosting";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_FEE_PRINCIPAL
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030ChargebackInterestFeePrincipal";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_PRINCIPAL_INTEREST_FEE
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030ChargebackPrincipalInterestFee";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_CHARGEBACK_INTEREST_PENALTY_FEE_PRINCIPAL
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030ChargebackInterestPenaltyFeePrincipal";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_ACTUAL_ACTUAL_INTEREST_RECALCULATION_DAILY
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmiActualActualInterestRecalculationDaily";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationAccelerateMaturityChargeOffBehaviour";
+ public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_ACCRUAL_ACTIVITY
=
"loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030AccrualActivity";
public static final String
DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_ACCELERATE_MATURITY_CHARGE_OFF_BEHAVIOUR
=
"loanProductCreateResponseLP2AdvancedPaymentAccelerateMaturityChargeOffBehaviour";
+ public static final String
LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST_RESPONSE =
"loanProductCreateResponseLP2NoInterestRecalculationChargebackAllocationInterestFirst";
+ public static final String
LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_PRINCIPAL_FIRST_RESPONSE =
"loanProductCreateResponseLP2NoInterestRecalculationChargebackAllocationPrincipalFirst";
public static final String CHARGE_FOR_LOAN_PERCENT_LATE_CREATE_RESPONSE =
"ChargeForLoanPercentLateCreateResponse";
public static final String
CHARGE_FOR_LOAN_PERCENT_LATE_AMOUNT_PLUS_INTEREST_CREATE_RESPONSE =
"ChargeForLoanPercentLateAmountPlusInterestCreateResponse";
public static final String
CHARGE_FOR_LOAN_PERCENT_PROCESSING_CREATE_RESPONSE =
"ChargeForLoanPercentProcessingCreateResponse";
@@ -159,6 +173,5 @@ public abstract class TestContextKey {
public static final String TRANSACTION_EVENT = "transactionEvent";
public static final String LOAN_WRITE_OFF_RESPONSE =
"loanWriteOffResponse";
public static final String LOAN_DELINQUENCY_ACTION_RESPONSE =
"loanDelinquencyActionResponse";
- public static final String
LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_INTEREST_FIRST_RESPONSE =
"loanProductCreateResponseLP2NoInterestRecalculationChargebackAllocationInterestFirst";
- public static final String
LP2_NO_INTEREST_RECALCULATION_CHARGEBACK_ALLOCATION_PRINCIPAL_FIRST_RESPONSE =
"loanProductCreateResponseLP2NoInterestRecalculationChargebackAllocationPrincipalFirst";
+ public static final String LOAN_TRANSACTION_RESPONSE =
"loanTransactionResponse";
}
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/LoanInterestPause.feature
b/fineract-e2e-tests-runner/src/test/resources/features/LoanInterestPause.feature
index 30eccde2d..40f0516fb 100644
---
a/fineract-e2e-tests-runner/src/test/resources/features/LoanInterestPause.feature
+++
b/fineract-e2e-tests-runner/src/test/resources/features/LoanInterestPause.feature
@@ -23,7 +23,7 @@ Feature: Loan interest pause on repayment schedule
And Admin successfully disburse the loan on "1 January 2024" with "100"
EUR transaction amount
When Admin sets the business date to "1 February 2024"
And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01
EUR transaction amount
- And Create interest pause period with start date "05 February 2024" and
end date "10 February 2024"
+ And Create an interest pause period with start date "05 February 2024" and
end date "10 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 | | |
|
@@ -59,7 +59,7 @@ Feature: Loan interest pause on repayment schedule
And Admin successfully disburse the loan on "1 January 2024" with "100"
EUR transaction amount
When Admin sets the business date to "1 February 2024"
And Customer makes "AUTOPAY" repayment on "01 February 2024" with 17.01
EUR transaction amount
- And Create interest pause period with start date "10 February 2024" and
end date "10 March 2024"
+ And Create an interest pause period with start date "10 February 2024" and
end date "10 March 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 | | |
|
@@ -113,7 +113,7 @@ Feature: Loan interest pause on repayment schedule
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 |
0.0 | 0.0 | 100.0 | false | false |
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 |
0.0 | 0.0 | 83.57 | false | false |
| 01 March 2024 | Repayment | 17.01 | 16.52 | 0.49 |
0.0 | 0.0 | 67.05 | false | false |
- And Create interest pause period with start date "05 February 2024" and
end date "10 February 2024"
+ And Create an interest pause period with start date "05 February 2024" and
end date "10 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 | | |
|
@@ -172,7 +172,7 @@ Feature: Loan interest pause on repayment schedule
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 |
0.0 | 0.0 | 100.0 | false | false |
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 |
0.0 | 0.0 | 83.57 | false | false |
| 01 March 2024 | Repayment | 17.01 | 16.52 | 0.49 |
0.0 | 0.0 | 67.05 | false | false |
- And Create interest pause period with start date "05 February 2024" and
end date "10 February 2024"
+ And Create an interest pause period with start date "05 February 2024" and
end date "10 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 | | |
|
@@ -190,7 +190,7 @@ Feature: Loan interest pause on repayment schedule
| 01 January 2024 | Disbursement | 100.0 | 0.0 | 0.0 |
0.0 | 0.0 | 100.0 | false | false |
| 01 February 2024 | Repayment | 17.01 | 16.43 | 0.58 |
0.0 | 0.0 | 83.57 | false | false |
| 01 March 2024 | Repayment | 17.01 | 16.62 | 0.39 |
0.0 | 0.0 | 66.95 | false | true |
- And Create interest pause period with start date "10 March 2024" and end
date "20 March 2024"
+ And Create an interest pause period with start date "10 March 2024" and
end date "20 March 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 | | |
|
@@ -230,7 +230,7 @@ Feature: Loan interest pause on repayment schedule
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
- And Create interest pause period with start date "10 February 2024" and
end date "10 March 2024"
+ And Create an interest pause period with start date "10 February 2024" and
end date "10 March 2024"
Then Loan term variations has 1 variation, with the following data:
| Term Type Id | Term Type Code | Term Type Value |
Applicable From | Decimal Value | Date Value | Is Specific To Installment |
Is Processed |
| 11 | loanTermType.interestPause | interestPause | 10
February 2024 | 0.0 | 10 March 2024 | false |
|
@@ -356,7 +356,7 @@ Feature: Loan interest pause on repayment schedule
| 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 |
| 14 January 2024 | Repayment | 17.01 | 16.77 | 0.24 |
0.0 | 0.0 | 83.23 | false | false |
- And Create interest pause period with start date "15 January 2024" and end
date "25 January 2024"
+ And Create an interest pause period with start date "15 January 2024" and
end date "25 January 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 | | |
|
diff --git
a/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature
b/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature
index c58cfc481..273ed680d 100644
--- a/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature
+++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature
@@ -186,16 +186,22 @@ Feature: LoanProduct
When Admin sets the business date to "12 December 2021"
When Admin creates a client with random data
And Admin successfully creates a new customised Loan submitted on date:
"12 December 2021", with Principal: "1000", a loanTermFrequency: 1 months, and
numberOfRepayments: 1
- Then Loan Product Charge-Off reasons options from loan product template
have 2 options, with the following data:
+ Then Loan Product Charge-Off reasons options from loan product template
have 5 options, with the following data:
| Charge-Off Reason Name | Description | Position | Is Active | Is
Mandatory |
| debit_card | | 0 | true | false
|
| credit_card | | 1 | true | false
|
+ | Fraud | | 2 | true | false
|
+ | Delinquent | | 3 | true | false
|
+ | Other | | 4 | true | false
|
Scenario: As a user I would like to verify Charge-Off reasons options in
specific loan product response
When Admin sets the business date to "12 December 2021"
When Admin creates a client with random data
And Admin successfully creates a new customised Loan submitted on date:
"12 December 2021", with Principal: "1000", a loanTermFrequency: 1 months, and
numberOfRepayments: 1
- Then Loan Product "LP1" Charge-Off reasons options from specific loan
product have 2 options, with the following data:
+ Then Loan Product "LP1" Charge-Off reasons options from specific loan
product have 5 options, with the following data:
| Charge-Off Reason Name | Description | Position | Is Active | Is
Mandatory |
| debit_card | | 0 | true | false
|
- | credit_card | | 1 | true | false
|
\ No newline at end of file
+ | credit_card | | 1 | true | false
|
+ | Fraud | | 2 | true | false
|
+ | Delinquent | | 3 | true | false
|
+ | Other | | 4 | true | false
|