FINERACT-2358: Advanced-accounting-rules-based-on-write-off-reason E2E tests

This commit is contained in:
Peter Kovacs
2025-10-15 09:52:16 +02:00
committed by Arnold Gálovics
parent c518d8622a
commit 3b62d562a2
14 changed files with 226 additions and 9 deletions
@@ -23,7 +23,7 @@ public enum DefaultCodeValue implements CodeValue {
// Charge-off reason
FRAUD("Fraud"), //
DELINQUENT("Delinquent"), //
OTHER("Other"); //
OTHER("Other"), BAD_DEBT("Bad Debt"), FORGIVEN("Forgiven"), TEST("Test"); //
private final String customName;
@@ -164,6 +164,7 @@ public enum DefaultLoanProduct implements LoanProduct {
LP2_ADV_PYMNT_INTEREST_DECL_BAL_SARP_EMI_360_30_NO_INT_RECALC_MULTIDISB_PARTIAL_PERIOD, //
LP2_ADV_PYMNT_INTEREST_DECL_BAL_SARP_EMI_360_30_NO_INT_RECALC_MULTIDISB_NO_PARTIAL_PERIOD, //
LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_MIN_INT_3_MAX_INT_20, //
LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_WRITE_OFF_REASON_MAP, //
;
@Override
@@ -107,9 +107,12 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep
public static final String CODE_VALUE_FAMILY_MARITAL_STATUS_WIDOWED = "Widowed";
public static final Long CODE_VALUE_CONSTITUTION_ID = 24L;
public static final String CODE_VALUE_CONSTITUTION_TEST = "Test";
public static final Long CODE_VALUE_RESCHEDULE_REASON_ID = 23L;
public static final String CODE_VALUE_RESCHEDULE_REASON_TEST = "Test";
public static final Long CODE_VALUE_WRITE_OFF_REASON_ID = 26L;
public static final String CODE_VALUE_WRITE_OFF_REASON_TEST_1 = "Bad Debt";
public static final String CODE_VALUE_WRITE_OFF_REASON_TEST_2 = "Forgiven";
public static final String CODE_VALUE_WRITE_OFF_REASON_TEST_3 = "Test";
private final CodesApi codesApi;
private final CodeValuesApi codeValuesApi;
@@ -246,6 +249,13 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep
List<String> rescheduleReasonNames = new ArrayList<>();
rescheduleReasonNames.add(CODE_VALUE_RESCHEDULE_REASON_TEST);
createCodeValues(CODE_VALUE_RESCHEDULE_REASON_ID, rescheduleReasonNames);
// add Write-off reasons
List<String> writeOffReasonNames = new ArrayList<>();
writeOffReasonNames.add(CODE_VALUE_WRITE_OFF_REASON_TEST_1);
writeOffReasonNames.add(CODE_VALUE_WRITE_OFF_REASON_TEST_2);
writeOffReasonNames.add(CODE_VALUE_WRITE_OFF_REASON_TEST_3);
createCodeValues(CODE_VALUE_WRITE_OFF_REASON_ID, writeOffReasonNames);
}
public void createCodeValues(Long codeId, List<String> codeValueNames) {
@@ -43,6 +43,7 @@ import org.apache.fineract.client.models.PaymentAllocationOrder;
import org.apache.fineract.client.models.PostClassificationToIncomeAccountMappings;
import org.apache.fineract.client.models.PostLoanProductsRequest;
import org.apache.fineract.client.models.PostLoanProductsResponse;
import org.apache.fineract.client.models.PostWriteOffReasonToExpenseAccountMappings;
import org.apache.fineract.client.services.LoanProductsApi;
import org.apache.fineract.test.data.AdvancePaymentsAdjustmentType;
import org.apache.fineract.test.data.ChargeProductType;
@@ -55,8 +56,12 @@ import org.apache.fineract.test.data.OverAppliedCalculationType;
import org.apache.fineract.test.data.PreClosureInterestCalculationRule;
import org.apache.fineract.test.data.RecalculationRestFrequencyType;
import org.apache.fineract.test.data.TransactionProcessingStrategyCode;
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.factory.LoanProductsRequestFactory;
import org.apache.fineract.test.helper.CodeHelper;
import org.apache.fineract.test.helper.Utils;
import org.apache.fineract.test.support.TestContext;
import org.apache.fineract.test.support.TestContextKey;
@@ -69,6 +74,8 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
private final LoanProductsApi loanProductsApi;
private final LoanProductsRequestFactory loanProductsRequestFactory;
private final CodeHelper codeHelper;
private final CodeValueResolver codeValueResolver;
@Override
public void initialize() throws Exception {
@@ -1319,7 +1326,7 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
.recalculationRestFrequencyType(1)//
.recalculationRestFrequencyInterval(1)//
.repaymentEvery(1)//
.interestRatePerPeriod((double) 7.0)//
.interestRatePerPeriod(7D)//
.interestRateFrequencyType(INTEREST_RATE_FREQUENCY_TYPE_MONTH)//
.enableDownPayment(false)//
.interestRecalculationCompoundingMethod(0)//
@@ -3818,6 +3825,56 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ
TestContext.INSTANCE.set(
TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PMNT_ALLOCATION_CAPITALIZED_INCOME_ADJ_CUSTOM_ALLOC_CLASSIFICATION_INCOME_MAP,
responseLoanProductsRequestLP2ProgressiveAdvPaymAllocCapitaizedIncomeClassificationIncomeMap);
// LP2 with progressive loan schedule + horizontal + interest EMI + 360/30
// + interest recalculation, buy down fees enabled
// + Write off reason expense map
final String name142 = DefaultLoanProduct.LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_WRITE_OFF_REASON_MAP.getName();
final Long writeOffReasonCodeId = codeHelper.retrieveCodeByName("WriteOffReasons").getId();
final CodeValue writeOffReasonCodeValueBadDebt = DefaultCodeValue.valueOf("BAD_DEBT");
final CodeValue writeOffReasonCodeValueForgiven = DefaultCodeValue.valueOf("FORGIVEN");
final CodeValue writeOffReasonCodeValueTest = DefaultCodeValue.valueOf("TEST");
long writeOffReasonIdBadDebt = codeValueResolver.resolve(writeOffReasonCodeId, writeOffReasonCodeValueBadDebt);
long writeOffReasonIdForgiven = codeValueResolver.resolve(writeOffReasonCodeId, writeOffReasonCodeValueForgiven);
long writeOffReasonIdTest = codeValueResolver.resolve(writeOffReasonCodeId, writeOffReasonCodeValueTest);
List<PostWriteOffReasonToExpenseAccountMappings> writeOffReasonToExpenseAccountMappings = new ArrayList<>();
PostWriteOffReasonToExpenseAccountMappings writeOffReasonToExpenseAccountMappingsBadDebt = new PostWriteOffReasonToExpenseAccountMappings();
writeOffReasonToExpenseAccountMappingsBadDebt.setWriteOffReasonCodeValueId(String.valueOf(writeOffReasonIdBadDebt));
writeOffReasonToExpenseAccountMappingsBadDebt.setExpenseAccountId("12"); // Credit Loss/Bad Debt
PostWriteOffReasonToExpenseAccountMappings writeOffReasonToExpenseAccountMappingsForgiven = new PostWriteOffReasonToExpenseAccountMappings();
writeOffReasonToExpenseAccountMappingsForgiven.setWriteOffReasonCodeValueId(String.valueOf(writeOffReasonIdForgiven));
writeOffReasonToExpenseAccountMappingsForgiven.setExpenseAccountId("23"); // Buy Down Expense
PostWriteOffReasonToExpenseAccountMappings writeOffReasonToExpenseAccountMappingsTest = new PostWriteOffReasonToExpenseAccountMappings();
writeOffReasonToExpenseAccountMappingsTest.setWriteOffReasonCodeValueId(String.valueOf(writeOffReasonIdTest));
writeOffReasonToExpenseAccountMappingsTest.setExpenseAccountId("16"); // Written off
writeOffReasonToExpenseAccountMappings.add(writeOffReasonToExpenseAccountMappingsBadDebt);
writeOffReasonToExpenseAccountMappings.add(writeOffReasonToExpenseAccountMappingsForgiven);
writeOffReasonToExpenseAccountMappings.add(writeOffReasonToExpenseAccountMappingsTest);
final PostLoanProductsRequest loanProductsRequestLP2ProgressiveAdvPaymentWriteOffReasonMap = loanProductsRequestFactory
.defaultLoanProductsRequestLP2BuyDownFees()//
.name(name142)//
.transactionProcessingStrategyCode(ADVANCED_PAYMENT_ALLOCATION.getValue())//
.loanScheduleType("PROGRESSIVE") //
.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")))//
.writeOffReasonsToExpenseMappings(writeOffReasonToExpenseAccountMappings);//
final Response<PostLoanProductsResponse> responseLoanProductsRequestLP2ProgressiveAdvPaymentWriteOffReasonMap = loanProductsApi
.createLoanProduct(loanProductsRequestLP2ProgressiveAdvPaymentWriteOffReasonMap).execute();
TestContext.INSTANCE.set(TestContextKey.DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PYMNT_WRITE_OFF_REASON_MAP,
responseLoanProductsRequestLP2ProgressiveAdvPaymentWriteOffReasonMap);
}
public static AdvancedPaymentData createPaymentAllocation(String transactionType, String futureInstallmentAllocationRule,
@@ -3286,6 +3286,28 @@ public class LoanStepDef extends AbstractStepDef {
ErrorHelper.checkSuccessfulApiCall(writeOffResponse);
}
@And("Admin does write-off the loan on {string} with write off reason: {string}")
public void writeOffLoan(String transactionDate, String writeOffReason) throws IOException {
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId = loanResponse.body().getLoanId();
final Long writeOffReasonCodeId = codeHelper.retrieveCodeByName("WriteOffReasons").getId();
final CodeValue writeOffReasonCodeValueBadDebt = DefaultCodeValue.valueOf(writeOffReason);
long writeOffReasonId = codeValueResolver.resolve(writeOffReasonCodeId, writeOffReasonCodeValueBadDebt);
PostLoansLoanIdTransactionsRequest writeOffRequest = new PostLoansLoanIdTransactionsRequest()//
.transactionDate(transactionDate)//
.writeoffReasonId(writeOffReasonId)//
.dateFormat(DATE_FORMAT)//
.locale(DEFAULT_LOCALE)//
.note("Write Off");//
Response<PostLoansLoanIdTransactionsResponse> writeOffResponse = loanTransactionsApi
.executeLoanTransaction(loanId, writeOffRequest, "writeoff").execute();
testContext().set(TestContextKey.LOAN_WRITE_OFF_RESPONSE, writeOffResponse);
ErrorHelper.checkSuccessfulApiCall(writeOffResponse);
}
@Then("Admin fails to undo {string}th transaction made on {string}")
public void undoTransaction(String nthTransaction, String transactionDate) throws IOException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
@@ -269,4 +269,5 @@ public abstract class TestContextKey {
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DECL_BAL_SARP_EMI_360_30_NO_INT_RECALC_MULTIDISB_NO_PARTIAL_PERIOD = "loanProductCreateResponseLP2AdvPmtIntDeclSarpEmi3630NoIntRecalcMutiDisbNoPartial";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PYMNT_INTEREST_RECALC_360_30_MULTIDISB_OVER_APPLIED_EXPECTED_TRANCHES = "loanProductCreateResponseLP2ProgressiveAdvancedPaymentInterestRecalculationMultidisbursalApprovedOverAppliedAmountExpectedTransches";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_EMI_360_30_INTEREST_RECALCULATION_DAILY_TILL_PRECLOSE_MIN_INT_3_MAX_INT_20 = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyEmi36030InterestRecalculationDailyTillPreCloseMinInt3MaxInt20";
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_PROGRESSIVE_ADV_PYMNT_WRITE_OFF_REASON_MAP = "loanProductCreateResponseLP2ProgressiveAdvancedPaymentWriteOffReasonMap";
}