From 8cbe90644fb0bb815d02adb8dda0409cfbccebca Mon Sep 17 00:00:00 2001 From: "adam.magyari" Date: Thu, 28 Nov 2024 18:38:26 +0100 Subject: [PATCH] FINERACT-2148: return loan charge off behaviour with loan details --- .../api/LoansApiResourceSwagger.java | 2 + .../loanaccount/data/LoanAccountData.java | 8 ++- .../service/LoanReadPlatformServiceImpl.java | 7 +- ...LoanProductWithChargeOffBehaviourTest.java | 70 +++++++++++++++++++ 4 files changed, 83 insertions(+), 4 deletions(-) create mode 100644 integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithChargeOffBehaviourTest.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index 3837c3fc7b..19ee3ac536 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -24,6 +24,7 @@ import java.util.List; import java.util.Set; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.data.StringEnumOptionData; import org.apache.fineract.portfolio.delinquency.api.DelinquencyApiResourceSwagger.GetDelinquencyRangesResponse; /** @@ -1202,6 +1203,7 @@ private GetLoansLoanIdLoanTermEnumData() {} public List emiAmountVariations; @Schema(description = "List of GetLoansLoanIdLoanTermVariations") public List loanTermVariations; + public StringEnumOptionData chargeOffBehaviour; } @Schema(description = "GetLoansResponse") diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java index 1b87b95596..8539c86055 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/data/LoanAccountData.java @@ -33,6 +33,7 @@ import lombok.experimental.Accessors; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.core.data.EnumOptionData; +import org.apache.fineract.infrastructure.core.data.StringEnumOptionData; import org.apache.fineract.infrastructure.core.domain.ExternalId; import org.apache.fineract.infrastructure.dataqueries.data.DatatableData; import org.apache.fineract.organisation.monetary.data.CurrencyData; @@ -269,6 +270,8 @@ public class LoanAccountData { private EnumOptionData loanScheduleType; private EnumOptionData loanScheduleProcessingType; + private StringEnumOptionData chargeOffBehaviour; + public static LoanAccountData importInstanceIndividual(EnumOptionData loanTypeEnumOption, Long clientId, Long productId, Long loanOfficerId, LocalDate submittedOnDate, Long fundId, BigDecimal principal, Integer numberOfRepayments, Integer repaymentEvery, EnumOptionData repaidEveryFrequencyEnums, Integer loanTermFrequency, @@ -453,7 +456,7 @@ public static LoanAccountData basicLoanDetails(final Long id, final String accou LocalDate lastClosedBusinessDate, LocalDate overpaidOnDate, final boolean chargedOff, final boolean enableDownPayment, final BigDecimal disbursedAmountPercentageForDownPayment, final boolean enableAutoRepaymentForDownPayment, final boolean enableInstallmentLevelDelinquency, final EnumOptionData loanScheduleType, - final EnumOptionData loanScheduleProcessingType, final Integer fixedLength) { + final EnumOptionData loanScheduleProcessingType, final Integer fixedLength, final StringEnumOptionData chargeOffBehaviour) { final CollectionData delinquent = CollectionData.template(); @@ -497,7 +500,8 @@ public static LoanAccountData basicLoanDetails(final Long id, final String accou .setEnableDownPayment(enableDownPayment).setDisbursedAmountPercentageForDownPayment(disbursedAmountPercentageForDownPayment) .setEnableAutoRepaymentForDownPayment(enableAutoRepaymentForDownPayment) .setEnableInstallmentLevelDelinquency(enableInstallmentLevelDelinquency).setLoanScheduleType(loanScheduleType) - .setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength); + .setLoanScheduleProcessingType(loanScheduleProcessingType).setFixedLength(fixedLength) + .setChargeOffBehaviour(chargeOffBehaviour); } /* diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index 652fe67f03..8b8bd49094 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -107,6 +107,7 @@ import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData; import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO; import org.apache.fineract.portfolio.loanaccount.domain.Loan; +import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeOffBehaviour; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory; import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper; @@ -702,7 +703,8 @@ public String loanSchema() { + " l.total_recovered_derived as totalRecovered, topuploan.account_no as closureLoanAccountNo, " + " topup.topup_amount as topupAmount, l.last_closed_business_date as lastClosedBusinessDate,l.overpaidon_date as overpaidOnDate, " + " l.is_charged_off as isChargedOff, l.charge_off_reason_cv_id as chargeOffReasonId, codec.code_value as chargeOffReason, l.charged_off_on_date as chargedOffOnDate, l.enable_down_payment as enableDownPayment, l.disbursed_amount_percentage_for_down_payment as disbursedAmountPercentageForDownPayment, l.enable_auto_repayment_for_down_payment as enableAutoRepaymentForDownPayment," - + " cobu.username as chargedOffByUsername, cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname, l.loan_schedule_type as loanScheduleType, l.loan_schedule_processing_type as loanScheduleProcessingType " + + " cobu.username as chargedOffByUsername, cobu.firstname as chargedOffByFirstname, cobu.lastname as chargedOffByLastname, l.loan_schedule_type as loanScheduleType, l.loan_schedule_processing_type as loanScheduleProcessingType, " + + " l.charge_off_behaviour as chargeOffBehaviour " // + " from m_loan l" // + " join m_product_loan lp on lp.id = l.product_id" // + " left join m_loan_recalculation_details lir on lir.loan_id = l.id join m_currency rc on rc." @@ -1066,6 +1068,7 @@ public LoanAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") fi final String loanScheduleProcessingTypeStr = rs.getString("loanScheduleProcessingType"); final LoanScheduleProcessingType loanScheduleProcessingType = LoanScheduleProcessingType.valueOf(loanScheduleProcessingTypeStr); final Integer fixedLength = JdbcSupport.getInteger(rs, "fixedLength"); + final LoanChargeOffBehaviour chargeOffBehaviour = LoanChargeOffBehaviour.valueOf(rs.getString("chargeOffBehaviour")); return LoanAccountData.basicLoanDetails(id, accountNo, status, externalId, clientId, clientAccountNo, clientName, clientOfficeId, clientExternalId, groupData, loanType, loanProductId, loanProductName, loanProductDescription, @@ -1084,7 +1087,7 @@ public LoanAccountData mapRow(final ResultSet rs, @SuppressWarnings("unused") fi fixedPrincipalPercentagePerInstallment, delinquencyRange, disallowExpectedDisbursements, isFraud, lastClosedBusinessDate, overpaidOnDate, isChargedOff, enableDownPayment, disbursedAmountPercentageForDownPayment, enableAutoRepaymentForDownPayment, enableInstallmentLevelDelinquency, loanScheduleType.asEnumOptionData(), - loanScheduleProcessingType.asEnumOptionData(), fixedLength); + loanScheduleProcessingType.asEnumOptionData(), fixedLength, chargeOffBehaviour.getValueAsStringEnumOptionData()); } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithChargeOffBehaviourTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithChargeOffBehaviourTest.java new file mode 100644 index 0000000000..363a310737 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanProductWithChargeOffBehaviourTest.java @@ -0,0 +1,70 @@ +/** + * 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.integrationtests; + +import java.math.BigDecimal; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.client.models.PostLoansResponse; +import org.apache.fineract.client.models.PutLoanProductsProductIdRequest; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class LoanProductWithChargeOffBehaviourTest extends BaseLoanIntegrationTest { + + private Long clientId; + private Long loanProductId; + private Long loanId; + + // create client, progressive loan product with charge-off behaviour REGULAR (default), loan with disburse limit + // 1000 for the client, + // and disburse 250 on 01 June 2024 + @BeforeEach + public void beforeEach() { + runAt("01 June 2024", () -> { + clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + final PostLoanProductsResponse loanProductsResponse = loanProductHelper.createLoanProduct(create4IProgressive()); + loanProductId = loanProductsResponse.getResourceId(); + PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan( + applyLP2ProgressiveLoanRequest(clientId, loanProductsResponse.getResourceId(), "01 June 2024", 1000.0, 10.0, 4, null)); + loanId = postLoansResponse.getLoanId(); + loanTransactionHelper.approveLoan(loanId, approveLoanRequest(1000.0, "01 June 2024")); + disburseLoan(loanId, BigDecimal.valueOf(250.0), "01 June 2024"); + }); + } + + @Test + public void testSavedToLoanNotChangingWithProduct() { + runAt("01 June 2024", () -> { + GetLoansLoanIdResponse loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertEquals("REGULAR", loanDetails.getChargeOffBehaviour().getId()); + + loanProductHelper.updateLoanProductById(loanProductId, + new PutLoanProductsProductIdRequest().chargeOffBehaviour("ZERO_INTEREST")); + final GetLoanProductsProductIdResponse loanProduct = loanTransactionHelper.getLoanProduct(loanProductId.intValue()); + Assertions.assertEquals("ZERO_INTEREST", loanProduct.getChargeOffBehaviour().getId()); + + loanDetails = loanTransactionHelper.getLoanDetails(loanId); + Assertions.assertEquals("REGULAR", loanDetails.getChargeOffBehaviour().getId()); + }); + } +}