FINERACT-2358: Advanced-accounting-rules-based-on-write-off-reason E2E tests
This commit is contained in:
committed by
Arnold Gálovics
parent
c518d8622a
commit
3b62d562a2
+4
@@ -106,4 +106,8 @@ public interface ProductToGLAccountMappingRepository
|
||||
ProductToGLAccountMapping findCapitalizedIncomeClassificationMapping(@Param("productId") Long productId,
|
||||
@Param("productType") Integer productType, @Param("classificationId") Long classificationId);
|
||||
|
||||
@Query("select mapping from ProductToGLAccountMapping mapping where mapping.writeOffReason.id = :writeOffReasonId AND mapping.productId = :productId AND mapping.productType = :productType")
|
||||
ProductToGLAccountMapping findWriteOffReasonMapping(@Param("productId") Long productId, @Param("productType") Integer productType,
|
||||
@Param("writeOffReasonId") Long writeOffReasonId);
|
||||
|
||||
}
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
|
||||
+1
@@ -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
|
||||
|
||||
+11
-1
@@ -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) {
|
||||
|
||||
+58
-1
@@ -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,
|
||||
|
||||
+22
@@ -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);
|
||||
|
||||
+1
@@ -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";
|
||||
}
|
||||
|
||||
@@ -361,3 +361,102 @@
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| EXPENSE | 744037 | Credit Loss/Bad Debt-Fraud | | 750.0 |
|
||||
| EXPENSE | e4 | Written off | 750.0 | |
|
||||
|
||||
@TestRailId:C4111
|
||||
Scenario: Verify GL entries for Write Off reason mapping - UC1: Write off, LP with write off reason mapping, NO write off reason to expense account
|
||||
When Admin sets the business date to "01 January 2025"
|
||||
And Admin creates a client with random data
|
||||
And Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_WRITE_OFF_REASON_MAP | 01 January 2025 | 1000 | 12 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 4 | MONTHS | 1 | MONTHS | 4 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025"
|
||||
And Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount
|
||||
And Admin sets the business date to "02 January 2025"
|
||||
And Admin runs inline COB job for Loan
|
||||
And Admin does write-off the loan on "02 January 2025"
|
||||
Then Loan status will be "CLOSED_WRITTEN_OFF"
|
||||
And Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2025 | 02 January 2025 | 753.72 | 246.28 | 10.0 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 28 | 01 March 2025 | 02 January 2025 | 504.98 | 248.74 | 7.54 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2025 | 02 January 2025 | 253.75 | 251.23 | 5.05 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 01 May 2025 | 02 January 2025 | 0.0 | 253.75 | 2.54 | 0.0 | 0.0 | 256.29 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 1000 | 25.13 | 0 | 0 | 1025.13 | 0 | 0 | 0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false |
|
||||
| 02 January 2025 | Close (as written-off) | 1025.13 | 1000.0 | 25.13 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
And Loan Transactions tab has a "WRITE_OFF" transaction with date "02 January 2025" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112601 | Loans Receivable | | 1000.0 |
|
||||
| ASSET | 112603 | Interest/Fee Receivable | | 25.13 |
|
||||
| EXPENSE | e4 | Written off | 1025.13 | |
|
||||
|
||||
@TestRailId:C4112
|
||||
Scenario: Verify GL entries for Write Off reason mapping - UC2: Write off, LP with write off reason mapping, with write off reason: Bad Debt
|
||||
When Admin sets the business date to "01 January 2025"
|
||||
And Admin creates a client with random data
|
||||
And Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_WRITE_OFF_REASON_MAP | 01 January 2025 | 1000 | 12 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 4 | MONTHS | 1 | MONTHS | 4 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025"
|
||||
And Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount
|
||||
And Admin sets the business date to "02 January 2025"
|
||||
And Admin runs inline COB job for Loan
|
||||
And Admin does write-off the loan on "02 January 2025" with write off reason: "BAD_DEBT"
|
||||
Then Loan status will be "CLOSED_WRITTEN_OFF"
|
||||
And Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2025 | 02 January 2025 | 753.72 | 246.28 | 10.0 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 28 | 01 March 2025 | 02 January 2025 | 504.98 | 248.74 | 7.54 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2025 | 02 January 2025 | 253.75 | 251.23 | 5.05 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 01 May 2025 | 02 January 2025 | 0.0 | 253.75 | 2.54 | 0.0 | 0.0 | 256.29 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 1000 | 25.13 | 0 | 0 | 1025.13 | 0 | 0 | 0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false |
|
||||
| 02 January 2025 | Close (as written-off) | 1025.13 | 1000.0 | 25.13 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
And Loan Transactions tab has a "WRITE_OFF" transaction with date "02 January 2025" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112601 | Loans Receivable | | 1000.0 |
|
||||
| ASSET | 112603 | Interest/Fee Receivable | | 25.13 |
|
||||
| EXPENSE | 744007 | Credit Loss/Bad Debt | 1025.13 | |
|
||||
|
||||
@TestRailId:C4113
|
||||
Scenario: Verify GL entries for Write Off reason mapping - UC3: Write off, LP without write off reason mapping, with write off reason: Bad Debt
|
||||
When Admin sets the business date to "01 January 2025"
|
||||
And Admin creates a client with random data
|
||||
And Admin creates a fully customized loan with the following data:
|
||||
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
|
||||
| LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES_CLASSIFICATION_INCOME_MAP | 01 January 2025 | 1000 | 12 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 4 | MONTHS | 1 | MONTHS | 4 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION |
|
||||
And Admin successfully approves the loan on "01 January 2025" with "1000" amount and expected disbursement date on "01 January 2025"
|
||||
And Admin successfully disburse the loan on "01 January 2025" with "1000" EUR transaction amount
|
||||
And Admin sets the business date to "02 January 2025"
|
||||
And Admin runs inline COB job for Loan
|
||||
And Admin does write-off the loan on "02 January 2025"
|
||||
Then Loan status will be "CLOSED_WRITTEN_OFF"
|
||||
And Loan Repayment schedule has 4 periods, with the following data for periods:
|
||||
| Nr | Days | Date | Paid date | Balance of loan | Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| | | 01 January 2025 | | 1000.0 | | | 0.0 | | 0.0 | 0.0 | | | |
|
||||
| 1 | 31 | 01 February 2025 | 02 January 2025 | 753.72 | 246.28 | 10.0 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 2 | 28 | 01 March 2025 | 02 January 2025 | 504.98 | 248.74 | 7.54 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 3 | 31 | 01 April 2025 | 02 January 2025 | 253.75 | 251.23 | 5.05 | 0.0 | 0.0 | 256.28 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
| 4 | 30 | 01 May 2025 | 02 January 2025 | 0.0 | 253.75 | 2.54 | 0.0 | 0.0 | 256.29 | 0.0 | 0.0 | 0.0 | 0.0 |
|
||||
And Loan Repayment schedule has the following data in Total row:
|
||||
| Principal due | Interest | Fees | Penalties | Due | Paid | In advance | Late | Outstanding |
|
||||
| 1000 | 25.13 | 0 | 0 | 1025.13 | 0 | 0 | 0 | 0.0 |
|
||||
And Loan Transactions tab has the following data:
|
||||
| Transaction date | Transaction Type | Amount | Principal | Interest | Fees | Penalties | Loan Balance | Reverted | Replayed |
|
||||
| 01 January 2025 | Disbursement | 1000.0 | 0.0 | 0.0 | 0.0 | 0.0 | 1000.0 | false | false |
|
||||
| 02 January 2025 | Close (as written-off) | 1025.13 | 1000.0 | 25.13 | 0.0 | 0.0 | 0.0 | false | false |
|
||||
And Loan Transactions tab has a "WRITE_OFF" transaction with date "02 January 2025" which has the following Journal entries:
|
||||
| Type | Account code | Account name | Debit | Credit |
|
||||
| ASSET | 112601 | Loans Receivable | | 1000.0 |
|
||||
| ASSET | 112603 | Interest/Fee Receivable | | 25.13 |
|
||||
| EXPENSE | e4 | Written off | 1025.13 | |
|
||||
+1
@@ -50,5 +50,6 @@ public class AccountingBridgeDataDTO {
|
||||
private boolean merchantBuyDownFee;
|
||||
private List<AdvancedMappingtDTO> buydownFeeClassificationCodeValue;
|
||||
private List<AdvancedMappingtDTO> capitalizedIncomeClassificationCodeValue;
|
||||
private AdvancedMappingtDTO writeOffReasonCodeValue;
|
||||
|
||||
}
|
||||
|
||||
+1
@@ -50,4 +50,5 @@ public class LoanDTO {
|
||||
private boolean merchantBuyDownFee;
|
||||
private List<AdvancedMappingtDTO> buydownFeeAdvancedMappingData;
|
||||
private List<AdvancedMappingtDTO> capitalizedIncomeAdvancedMappingData;
|
||||
private AdvancedMappingtDTO writeOffReasonAdvancedMappingData;
|
||||
}
|
||||
|
||||
+7
-2
@@ -174,7 +174,7 @@ public class AccountingProcessorHelper {
|
||||
periodicAccrualBasedAccountingEnabled, newLoanTransactions, isLoanMarkedAsChargeOff, isLoanMarkedAsFraud,
|
||||
chargeOffReasonCodeValue, isLoanMarkedAsWrittenOff, merchantBuyDownFee,
|
||||
accountingBridgeData.getBuydownFeeClassificationCodeValue(),
|
||||
accountingBridgeData.getCapitalizedIncomeClassificationCodeValue());
|
||||
accountingBridgeData.getCapitalizedIncomeClassificationCodeValue(), accountingBridgeData.getWriteOffReasonCodeValue());
|
||||
}
|
||||
|
||||
public ProductToGLAccountMapping getChargeOffMappingByCodeValue(Long loanProductId, PortfolioProductType productType,
|
||||
@@ -182,6 +182,11 @@ public class AccountingProcessorHelper {
|
||||
return accountMappingRepository.findChargeOffReasonMapping(loanProductId, productType.getValue(), chargeOffReasonId);
|
||||
}
|
||||
|
||||
public ProductToGLAccountMapping getWriteOffMappingByCodeValue(Long loanProductId, PortfolioProductType productType,
|
||||
Long writeOffReasonId) {
|
||||
return accountMappingRepository.findWriteOffReasonMapping(loanProductId, productType.getValue(), writeOffReasonId);
|
||||
}
|
||||
|
||||
public ProductToGLAccountMapping getClassificationMappingByCodeValue(Long loanProductId, PortfolioProductType productType,
|
||||
final Long classificationId, final String classificationType) {
|
||||
if (LoanProductAccountingParams.BUYDOWN_FEE_CLASSIFICATION_TO_INCOME_ACCOUNT_MAPPINGS.getValue().equals(classificationType)) {
|
||||
@@ -937,7 +942,7 @@ public class AccountingProcessorHelper {
|
||||
persistJournalEntry(journalEntry);
|
||||
}
|
||||
|
||||
private void createDebitJournalEntryForLoan(final Office office, final String currencyCode, final GLAccount account, final Long loanId,
|
||||
public void createDebitJournalEntryForLoan(final Office office, final String currencyCode, final GLAccount account, final Long loanId,
|
||||
final String transactionId, final LocalDate transactionDate, final BigDecimal amount) {
|
||||
final boolean manualEntry = false;
|
||||
Long loanTransactionId = null;
|
||||
|
||||
+14
-2
@@ -1913,8 +1913,20 @@ public class AccrualBasedAccountingProcessorForLoan implements AccountingProcess
|
||||
* Single DEBIT transaction for write-offs
|
||||
***/
|
||||
if (MathUtil.isGreaterThanZero(totalDebitAmount)) {
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
final AdvancedMappingtDTO writeAdvancedMappingtDTO = loanDTO.getWriteOffReasonAdvancedMappingData();
|
||||
final ProductToGLAccountMapping mapping = (writeAdvancedMappingtDTO != null
|
||||
&& writeAdvancedMappingtDTO.getReferenceValueId() != null)
|
||||
? helper.getWriteOffMappingByCodeValue(loanProductId, PortfolioProductType.LOAN,
|
||||
writeAdvancedMappingtDTO.getReferenceValueId())
|
||||
: null;
|
||||
|
||||
if (mapping == null) {
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, AccrualAccountsForLoan.LOSSES_WRITTEN_OFF.getValue(),
|
||||
loanProductId, paymentTypeId, loanId, transactionId, transactionDate, totalDebitAmount);
|
||||
} else {
|
||||
this.helper.createDebitJournalEntryForLoan(office, currencyCode, mapping.getGlAccount(), loanId, transactionId,
|
||||
transactionDate, totalDebitAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+5
-1
@@ -872,13 +872,17 @@ public class JournalEntryWritePlatformServiceJpaRepositoryImpl implements Journa
|
||||
} else if (loanTransaction.isCapitalizedIncomeAmortization()) {
|
||||
capitalizedIncomeAdvancedMappingData = getLoanTransactionClassificationId(loanTransaction);
|
||||
}
|
||||
AdvancedMappingtDTO writeOffReasonAdvancedMappingData = null;
|
||||
if (loan.isClosedWrittenOff() && loan.getWriteOffReason() != null) {
|
||||
writeOffReasonAdvancedMappingData = new AdvancedMappingtDTO(loan.getWriteOffReason().getId(), BigDecimal.ZERO);
|
||||
}
|
||||
|
||||
return new AccountingBridgeDataDTO(loan.getId(), loan.productId(), loan.getOfficeId(), currencyCode,
|
||||
loan.getSummary().getTotalInterestCharged(), loan.isCashBasedAccountingEnabledOnLoanProduct(),
|
||||
loan.isUpfrontAccrualAccountingEnabledOnLoanProduct(), loan.isPeriodicAccrualAccountingEnabledOnLoanProduct(),
|
||||
isAccountTransfer, wasChargedOffAtTransactionTime, loan.isFraud(), loan.fetchChargeOffReasonId(), loan.isClosedWrittenOff(),
|
||||
transactions, loan.getLoanProductRelatedDetail().isMerchantBuyDownFee(), buydownFeeAdvancedMappingData,
|
||||
capitalizedIncomeAdvancedMappingData);
|
||||
capitalizedIncomeAdvancedMappingData, writeOffReasonAdvancedMappingData);
|
||||
}
|
||||
|
||||
private List<AdvancedMappingtDTO> getLoanTransactionClassificationId(final LoanTransaction loanTransaction) {
|
||||
|
||||
+1
-1
@@ -73,7 +73,7 @@ class CreateJournalEntriesForChargeOffLoanTest {
|
||||
Collections.emptyList(), false, "", null, null, null, null);
|
||||
|
||||
loanDTO = new LoanDTO(1L, 1L, 1L, "USD", false, true, true, List.of(loanTransactionDTO), false, false, chargeOffReasonId, false,
|
||||
false, null, null);
|
||||
false, null, null, null);
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user