From 0891adb267c762d1b396e7f83ac92a86244655b8 Mon Sep 17 00:00:00 2001 From: Adam Saghy Date: Fri, 16 Jan 2026 13:07:23 +0100 Subject: [PATCH] FINERACT-2421: Rework code value handling in E2E --- .../service/CommandWrapperBuilder.java | 26 ++++ .../codes/domain/CodeValueRepository.java | 3 + .../service/CodeReadPlatformService.java | 2 +- .../service/CodeValueReadPlatformService.java | 4 + .../test/data/codevalue/CodeNames.java | 58 +++++++++ .../data/codevalue/CodeValueResolver.java | 16 ++- .../test/data/codevalue/DefaultCodeValue.java | 5 +- .../test/stepdef/loan/LoanStepDef.java | 49 ++----- .../global/CodeGlobalInitializerStep.java | 120 ++++++++---------- .../LoanProductGlobalInitializerStep.java | 10 +- .../features/LoanBuyDownFees.feature | 10 +- .../features/LoanCapitalizedIncome.feature | 14 +- .../resources/features/LoanProduct.feature | 20 ++- .../codes/api/CodeValuesApiResource.java | 98 +++++++++++++- .../codes/api/CodesApiResource.java | 2 +- .../service/CodeReadPlatformServiceImpl.java | 2 +- .../CodeValueReadPlatformServiceImpl.java | 31 ++++- .../service/DatatableWriteServiceImpl.java | 6 +- 18 files changed, 328 insertions(+), 148 deletions(-) create mode 100644 fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeNames.java diff --git a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java index 9f3d7586d..d2453dd9c 100644 --- a/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java +++ b/fineract-core/src/main/java/org/apache/fineract/commands/service/CommandWrapperBuilder.java @@ -1257,6 +1257,14 @@ public class CommandWrapperBuilder { return this; } + public CommandWrapperBuilder createCodeValue(final Long codeId, String codeName) { + this.actionName = "CREATE"; + this.entityName = "CODEVALUE"; + this.entityId = codeId; + this.href = "/codes/name/" + codeName + "/codevalues/template"; + return this; + } + public CommandWrapperBuilder updateCodeValue(final Long codeId, final Long codeValueId) { this.actionName = "UPDATE"; this.entityName = "CODEVALUE"; @@ -1266,6 +1274,15 @@ public class CommandWrapperBuilder { return this; } + public CommandWrapperBuilder updateCodeValue(String codeName, Long codeId, Long codeValueId) { + this.actionName = "UPDATE"; + this.entityName = "CODEVALUE"; + this.entityId = codeId; + this.subentityId = codeValueId; + this.href = "/codes/name/" + codeName + "/codevalues/" + codeValueId; + return this; + } + public CommandWrapperBuilder deleteCodeValue(final Long codeId, final Long codeValueId) { this.actionName = "DELETE"; this.entityName = "CODEVALUE"; @@ -1275,6 +1292,15 @@ public class CommandWrapperBuilder { return this; } + public CommandWrapperBuilder deleteCodeValue(String codeName, Long codeId, Long codeValueId) { + this.actionName = "DELETE"; + this.entityName = "CODEVALUE"; + this.entityId = codeId; + this.subentityId = codeValueId; + this.href = "/codes/name/" + codeName + "/codevalues/" + codeValueId; + return this; + } + public CommandWrapperBuilder createGLClosure() { this.actionName = "CREATE"; this.entityName = "GLCLOSURE"; diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/domain/CodeValueRepository.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/domain/CodeValueRepository.java index 60ba58e54..fbff80ae0 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/domain/CodeValueRepository.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/domain/CodeValueRepository.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.infrastructure.codes.domain; +import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.JpaSpecificationExecutor; @@ -26,4 +27,6 @@ public interface CodeValueRepository extends JpaRepository, Jpa CodeValue findByCodeNameAndId(String codeName, Long id); CodeValue findByCodeNameAndLabel(String codeName, String label); + + List findByCodeName(String codeName); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformService.java index 67d10caea..b2c5340ff 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformService.java @@ -27,5 +27,5 @@ public interface CodeReadPlatformService { CodeData retrieveCode(Long codeId); - CodeData retriveCode(String codeName); + CodeData retrieveCode(String codeName); } diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformService.java index f56a9ddc8..7243bfba3 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformService.java @@ -46,4 +46,8 @@ public interface CodeValueReadPlatformService { Collection retrieveAllCodeValues(Long codeId); CodeValueData retrieveCodeValue(Long codeValueId); + + List retrieveAllCodeValues(String codeName); + + CodeValueData retrieveCodeValue(String codeName, Long codeValueId); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeNames.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeNames.java new file mode 100644 index 000000000..e10df2afa --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/CodeNames.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 lombok.Getter; +import lombok.RequiredArgsConstructor; + +@Getter +@RequiredArgsConstructor +public enum CodeNames { + + FINANCIAL_INSTRUMENT("financial_instrument"), // + TRANSACTION_TYPE("transaction_type"), // + BANKRUPTCY_TAG("bankruptcy_tag"), // + PENDING_FRAUD_TAG("pending_fraud_tag"), // + PENDING_DECEASED_TAG("pending_deceased_tag"), // + HARDSHIP_TAG("hardship_tag"), // + ACTIVE_DUTY_TAG("active_duty_tag"), // + ADDRESS_TYPE("ADDRESS_TYPE"), // + COUNTRY("COUNTRY"), // + STATE("STATE"), // + CHARGE_OFF("ChargeOffReasons"), // + CUSTOMER_IDENTIFIER("Customer Identifier"), // + GENDER("Gender"), // + CLIENT_TYPE("ClientType"), // + CLIENT_CLASSIFICATION("ClientClassification"), // + FAMILY_MEMBER_RELATIONSHIP("RELATIONSHIP"), // + FAMILY_MEMBER_PROFESSION("PROFESSION"), // + FAMILY_MARITAL_STATUS("MARITAL STATUS"), // + CONSTITUTION("Constitution"), // + LOAN_RESCHEDULE_REASON("LoanRescheduleReason"), // + WRITE_OFF_REASON("WriteOffReasons"), // + BUYDOWN_FEE_TRANSACTION_CLASSIFICATION("buydown_fee_transaction_classification"), // + CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION("capitalized_income_transaction_classification"); // + + private final String value; + + @Override + public String toString() { + return value; + } +} 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 index 2875b1468..0c8409d5b 100644 --- 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 @@ -36,14 +36,26 @@ public class CodeValueResolver { private final FineractFeignClient fineractClient; - @Cacheable(key = "#codeValue.getName()", value = "codeValuesByName") + @Cacheable(key = "#codeId + '-' + #codeValue", value = "codeValuesByName") public long resolve(Long codeId, CodeValue codeValue) { String codeValueName = codeValue.getName(); log.debug("Resolving code value by code id and name [{}]", codeValue); List codeValuesResponses = ok(() -> fineractClient.codeValues().retrieveAllCodeValues(codeId, Map.of())); GetCodeValuesDataResponse foundPtr = codeValuesResponses.stream().filter(ptr -> codeValueName.equals(ptr.getName())).findAny() - .orElseThrow(() -> new IllegalArgumentException("Payment type [%s] not found".formatted(codeValueName))); + .orElseThrow( + () -> new IllegalArgumentException("Code Value [%s] not found for Code [%s]".formatted(codeValueName, codeId))); + + return foundPtr.getId(); + } + + @Cacheable(key = "#codeName + '-' + #codeValue", value = "codeValuesByName") + public long resolve(String codeName, String codeValue) { + log.debug("Resolving code value by code id and name [{}]", codeValue); + List codeValuesResponses = ok( + () -> fineractClient.codeValues().retrieveAllCodeValues1(codeName, Map.of())); + GetCodeValuesDataResponse foundPtr = codeValuesResponses.stream().filter(ptr -> codeValue.equals(ptr.getName())).findAny() + .orElseThrow(() -> new IllegalArgumentException("Code Value [%s] not found for Code [%s]".formatted(codeValue, codeName))); return foundPtr.getId(); } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java index 59d77da1e..29cfe91fa 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/data/codevalue/DefaultCodeValue.java @@ -23,7 +23,10 @@ public enum DefaultCodeValue implements CodeValue { // Charge-off reason FRAUD("Fraud"), // DELINQUENT("Delinquent"), // - OTHER("Other"), BAD_DEBT("Bad Debt"), FORGIVEN("Forgiven"), TEST("Test"); // + OTHER("Other"), // + BAD_DEBT("Bad Debt"), // + FORGIVEN("Forgiven"), // + TEST("Test"); // private final String customName; 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 cf0bc2ac9..f9302c6e5 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 @@ -79,7 +79,6 @@ import org.apache.fineract.client.models.CommandProcessingResult; import org.apache.fineract.client.models.DeleteLoansLoanIdResponse; import org.apache.fineract.client.models.DisbursementDetail; import org.apache.fineract.client.models.GetCodeValuesDataResponse; -import org.apache.fineract.client.models.GetCodesResponse; import org.apache.fineract.client.models.GetLoanProductsChargeOffReasonOptions; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoanProductsResponse; @@ -105,8 +104,6 @@ import org.apache.fineract.client.models.OldestCOBProcessedLoanDTO; import org.apache.fineract.client.models.PaymentAllocationOrder; import org.apache.fineract.client.models.PostAddAndDeleteDisbursementDetailRequest; import org.apache.fineract.client.models.PostClientsResponse; -import org.apache.fineract.client.models.PostCodeValueDataResponse; -import org.apache.fineract.client.models.PostCodeValuesDataRequest; import org.apache.fineract.client.models.PostLoansDisbursementData; import org.apache.fineract.client.models.PostLoansLoanIdRequest; import org.apache.fineract.client.models.PostLoansLoanIdResponse; @@ -131,6 +128,7 @@ 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.CodeNames; import org.apache.fineract.test.data.codevalue.CodeValue; import org.apache.fineract.test.data.codevalue.CodeValueResolver; import org.apache.fineract.test.data.codevalue.DefaultCodeValue; @@ -4879,14 +4877,6 @@ public class LoanStepDef extends AbstractStepDef { testContext().set(TestContextKey.LOAN_CAPITALIZED_INCOME_RESPONSE, capitalizedIncomeResponse); } - @And("Admin adds capitalized income with {string} payment type to the loan on {string} with {string} EUR transaction amount and classification: scheduled_payment") - public void adminAddsCapitalizedIncomeToTheLoanOnWithEURTransactionAmountWithClassificationScheduledPayment( - final String transactionPaymentType, final String transactionDate, final String amount) { - final PostLoansLoanIdTransactionsResponse capitalizedIncomeResponse = addCapitalizedIncomeToTheLoanOnWithEURTransactionAmountWithClassificationScheduledPayment( - transactionPaymentType, transactionDate, amount); - testContext().set(TestContextKey.LOAN_CAPITALIZED_INCOME_RESPONSE, capitalizedIncomeResponse); - } - @And("Admin adds capitalized income with {string} payment type to the loan on {string} with {string} EUR transaction amount and {string} classification") public void adminAddsCapitalizedIncomeWithClassification(final String transactionPaymentType, final String transactionDate, final String amount, final String classificationCodeName) { @@ -4904,7 +4894,8 @@ public class LoanStepDef extends AbstractStepDef { final Long paymentTypeValue = paymentTypeResolver.resolve(paymentType); // Get classification code value - final Long classificationId = getClassificationCodeValueId(classificationCodeName); + final Long classificationId = getClassificationCodeValueId(CodeNames.CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION.getValue(), + classificationCodeName); final PostLoansLoanIdTransactionsRequest capitalizedIncomeRequest = LoanRequestFactory.defaultCapitalizedIncomeRequest() .transactionDate(transactionDate).transactionAmount(Double.valueOf(amount)).paymentTypeId(paymentTypeValue) @@ -5373,24 +5364,16 @@ public class LoanStepDef extends AbstractStepDef { testContext().set(TestContextKey.LOAN_BUY_DOWN_FEE_RESPONSE, buyDownFeesIncomeResponse); } - @And("Admin adds buy down fee with {string} payment type to the loan on {string} with {string} EUR transaction amount and classification: pending_bankruptcy") - public void adminAddsBuyDownFeesToTheLoanOnWithEURTransactionAmountWithClassification(final String transactionPaymentType, - final String transactionDate, final String amount) { - final PostLoansLoanIdTransactionsResponse buyDownFeesIncomeResponse = addBuyDownFeeToTheLoanOnWithEURTransactionAmountWithClassification( - transactionPaymentType, transactionDate, amount); - testContext().set(TestContextKey.LOAN_BUY_DOWN_FEE_RESPONSE, buyDownFeesIncomeResponse); - } - @When("Admin adds buy down fee with {string} payment type to the loan on {string} with {string} EUR transaction amount and {string} classification") public void adminAddsBuyDownFeeWithClassification(final String transactionPaymentType, final String transactionDate, - final String amount, final String classificationCodeName) { + final String amount, final String classificationCodeValueName) { final PostLoansLoanIdTransactionsResponse buyDownFeesIncomeResponse = addBuyDownFeeWithClassification(transactionPaymentType, - transactionDate, amount, classificationCodeName); + transactionDate, amount, classificationCodeValueName); testContext().set(TestContextKey.LOAN_BUY_DOWN_FEE_RESPONSE, buyDownFeesIncomeResponse); } public PostLoansLoanIdTransactionsResponse addBuyDownFeeWithClassification(final String transactionPaymentType, - final String transactionDate, final String amount, final String classificationCodeName) { + final String transactionDate, final String amount, final String classificationCodeValueName) { final PostLoansResponse loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE); final long loanId = loanResponse.getLoanId(); @@ -5398,7 +5381,8 @@ public class LoanStepDef extends AbstractStepDef { final Long paymentTypeValue = paymentTypeResolver.resolve(paymentType); // Get classification code value - final Long classificationId = getClassificationCodeValueId(classificationCodeName); + final Long classificationId = getClassificationCodeValueId(CodeNames.BUYDOWN_FEE_TRANSACTION_CLASSIFICATION.getValue(), + classificationCodeValueName); final PostLoansLoanIdTransactionsRequest buyDownFeeRequest = LoanRequestFactory.defaultBuyDownFeeIncomeRequest() .transactionDate(transactionDate).transactionAmount(Double.valueOf(amount)).paymentTypeId(paymentTypeValue) @@ -5740,27 +5724,18 @@ public class LoanStepDef extends AbstractStepDef { .isEqualTo(expectedClassification); } - private Long getClassificationCodeValueId(String classificationName) { - final GetCodesResponse code = codeHelper.retrieveCodeByName(classificationName); - + private Long getClassificationCodeValueId(String codeName, String codeValueName) { // Check if code value already exists - List existingCodeValues = fineractClient.codeValues().retrieveAllCodeValues(code.getId()); - String codeValueName = classificationName + "_value"; - + List existingCodeValues = fineractClient.codeValues().retrieveAllCodeValues1(codeName); // Try to find existing code value with the same name for (GetCodeValuesDataResponse codeValue : existingCodeValues) { if (codeValueName.equals(codeValue.getName())) { - log.info("Reusing existing code value: {}", codeValueName); + log.debug("Reusing existing code value: {}", codeValueName); return codeValue.getId(); } } - // If not found, create a new code value - PostCodeValuesDataRequest codeValueRequest = new PostCodeValuesDataRequest().name(codeValueName).isActive(true).position(1); - - PostCodeValueDataResponse response = codeHelper.createCodeValue(code.getId(), codeValueRequest); - - return response.getSubResourceId(); + throw new IllegalStateException(String.format("Code [%s] with code value [%s] cannot be found", codeName, codeValueName)); } @And("Loan Amortization Allocation Mapping for {string} transaction created on {string} contains the following data:") diff --git a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java index 983099fc2..24bb9b699 100644 --- a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java +++ b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/CodeGlobalInitializerStep.java @@ -30,6 +30,7 @@ import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.PostCodeValuesDataRequest; import org.apache.fineract.client.models.PostCodesRequest; import org.apache.fineract.client.models.PutCodeValuesDataRequest; +import org.apache.fineract.test.data.codevalue.CodeNames; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.stereotype.Component; @@ -40,44 +41,26 @@ import org.springframework.stereotype.Component; @Order(Ordered.HIGHEST_PRECEDENCE) public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep { - public static final String CODE_NAME_FINANCIAL_INSTRUMENT = "financial_instrument"; - public static final String CODE_NAME_TRANSACTION_TYPE = "transaction_type"; - public static final String CODE_NAME_BANKRUPTCY_TAG = "bankruptcy_tag"; - public static final String CODE_NAME_PENDING_FRAUD_TAG = "pending_fraud_tag"; - public static final String CODE_NAME_PENDING_DECEASED_TAG = "pending_deceased_tag"; - public static final String CODE_NAME_HARDSHIP_TAG = "hardship_tag"; - public static final String CODE_NAME_ACTIVE_DUTY_TAG = "active_duty_tag"; - public static final Long CODE_VALUE_ADDRESS_TYPE_ID = 29L; public static final String CODE_VALUE_ADDRESS_TYPE_RESIDENTIAL = "Residential address"; public static final String CODE_VALUE_ADDRESS_TYPE_OFFICE = "Office address"; - public static final Long CODE_VALUE_COUNTRY_ID = 28L; public static final String CODE_VALUE_COUNTRY_GERMANY = "Germany"; - public static final Long CODE_VALUE_STATE_ID = 27L; public static final String CODE_VALUE_STATE_BERLIN = "Berlin"; - 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_CHARGE_OFF_REASON_FRAUD = "Fraud"; + public static final String CODE_VALUE_CHARGE_OFF_REASON_DELINQUENT = "Delinquent"; + public static final String CODE_VALUE_CHARGE_OFF_REASON_OTHER = "Other"; public static final String CODE_VALUE_TRANSACTION_TYPE_SCHEDULED_PAYMENT = "scheduled_payment"; - public static final Long CODE_VALUE_BANKRUPTCY_TAG_ID = 41L; public static final String CODE_VALUE_BANKRUPTCY_TAG_PENDING = "pending_bankruptcy"; public static final String CODE_VALUE_BANKRUPTCY_TAG_BANKRUPTCY = "bankruptcy"; - public static final Long CODE_VALUE_PENDING_FRAUD_TAG_ID = 42L; public static final String CODE_VALUE_PENDING_FRAUD_TAG_PENDING = "pending_fraud"; public static final String CODE_VALUE_PENDING_FRAUD_TAG_FRAUD = "fraud"; - public static final Long CODE_VALUE_PENDING_DECEASED_TAG_ID = 43L; public static final String CODE_VALUE_PENDING_DECEASED_TAG_PENDING = "pending_deceased"; public static final String CODE_VALUE_PENDING_DECEASED_TAG_DECEASED = "deceased"; - public static final Long CODE_VALUE_HARDSHIP_TAG_ID = 44L; public static final String CODE_VALUE_HARDSHIP_TAG_ACTIVE = "active"; public static final String CODE_VALUE_HARDSHIP_TAG_INACTIVE = "inactive"; - public static final Long CODE_VALUE_ACTIVE_DUTY_TAG_ID = 45L; public static final String CODE_VALUE_ACTIVE_DUTY_TAG_ACTIVE = "active"; public static final String CODE_VALUE_ACTIVE_DUTY_TAG_INACTIVE = "inactive"; - public static final Long CODE_VALUE_CUSTOMER_IDENTIFIERS_ID = 1L; public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_1 = "Passport"; public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_2 = "Id"; public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_3 = "Drivers License"; @@ -86,37 +69,30 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_6 = "TIN"; public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_7 = "ITIN"; public static final String CODE_VALUE_CUSTOMER_IDENTIFIERS_8 = "EIN"; - public static final Long CODE_VALUE_GENDER_ID = 4L; public static final String CODE_VALUE_GENDER_FEMALE = "Female"; public static final String CODE_VALUE_GENDER_MALE = "Male"; - public static final Long CODE_VALUE_CLIENT_TYPE_ID = 16L; public static final String CODE_VALUE_CLIENT_TYPE_CORPORATE = "Corporate"; public static final String CODE_VALUE_CLIENT_TYPE_LEGAL = "Legal"; public static final String CODE_VALUE_CLIENT_TYPE_NON_LEGAL = "Non-legal"; - public static final Long CODE_VALUE_CLIENT_CLASSIFICATION_ID = 17L; public static final String CODE_VALUE_CLIENT_CLASSIFICATION_LAWYER = "Lawyer"; public static final String CODE_VALUE_CLIENT_CLASSIFICATION_DIRECTOR = "Director"; public static final String CODE_VALUE_CLIENT_CLASSIFICATION_NONE = "None"; - public static final Long CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_ID = 31L; public static final String CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_SPOUSE = "Spouse"; public static final String CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_FATHER = "Father"; public static final String CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_MOTHER = "Mother"; public static final String CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_CHILD = "Child"; - public static final Long CODE_VALUE_FAMILY_MEMBER_PROFESSION_ID = 32L; public static final String CODE_VALUE_FAMILY_MEMBER_PROFESSION_EMPLOYEE = "Employee"; public static final String CODE_VALUE_FAMILY_MEMBER_PROFESSION_SELF_EMPLOYED = "Self-Employed"; - public static final Long CODE_VALUE_FAMILY_MARITAL_STATUS_ID = 30L; public static final String CODE_VALUE_FAMILY_MARITAL_STATUS_MARRIED = "Married"; public static final String CODE_VALUE_FAMILY_MARITAL_STATUS_SINGLE = "Single"; 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"; + public static final String BUYDOWN_FEE_TRANSACTION_CLASSIFICATION_VALUE = "buydown_fee_transaction_classification_value"; + public static final String CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION_VALUE = "capitalized_income_transaction_classification_value"; private final FineractFeignClient fineractClient; @@ -131,61 +107,64 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep List addressNames = new ArrayList<>(); addressNames.add(CODE_VALUE_ADDRESS_TYPE_RESIDENTIAL); addressNames.add(CODE_VALUE_ADDRESS_TYPE_OFFICE); - createCodeValues(CODE_VALUE_ADDRESS_TYPE_ID, addressNames); + createCodeValues(CodeNames.ADDRESS_TYPE.getValue(), addressNames); // Country List countryNames = new ArrayList<>(); countryNames.add(CODE_VALUE_COUNTRY_GERMANY); - createCodeValues(CODE_VALUE_COUNTRY_ID, countryNames); + createCodeValues(CodeNames.COUNTRY.getValue(), countryNames); // State List stateNames = new ArrayList<>(); stateNames.add(CODE_VALUE_STATE_BERLIN); - createCodeValues(CODE_VALUE_STATE_ID, stateNames); + createCodeValues(CodeNames.STATE.getValue(), stateNames); // financial instrument List 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); + createCodeValues(CodeNames.FINANCIAL_INSTRUMENT.getValue(), financialInstrumentNames); + + List chargeOffReasonNames = new ArrayList<>(); + chargeOffReasonNames.add(CODE_VALUE_CHARGE_OFF_REASON_FRAUD); + chargeOffReasonNames.add(CODE_VALUE_CHARGE_OFF_REASON_DELINQUENT); + chargeOffReasonNames.add(CODE_VALUE_CHARGE_OFF_REASON_OTHER); + createCodeValues(CodeNames.CHARGE_OFF.getValue(), chargeOffReasonNames); // transaction type List transactionTypeNames = new ArrayList<>(); transactionTypeNames.add(CODE_VALUE_TRANSACTION_TYPE_SCHEDULED_PAYMENT); - createCodeValues(CODE_VALUE_TRANSACTION_TYPE_ID, transactionTypeNames); + createCodeValues(CodeNames.TRANSACTION_TYPE.getValue(), transactionTypeNames); // bankruptcy tag List bankruptcyTagNames = new ArrayList<>(); bankruptcyTagNames.add(CODE_VALUE_BANKRUPTCY_TAG_PENDING); bankruptcyTagNames.add(CODE_VALUE_BANKRUPTCY_TAG_BANKRUPTCY); - createCodeValues(CODE_VALUE_BANKRUPTCY_TAG_ID, bankruptcyTagNames); + createCodeValues(CodeNames.BANKRUPTCY_TAG.getValue(), bankruptcyTagNames); // pending fraud tag List pendingFraudTagNames = new ArrayList<>(); pendingFraudTagNames.add(CODE_VALUE_PENDING_FRAUD_TAG_PENDING); pendingFraudTagNames.add(CODE_VALUE_PENDING_FRAUD_TAG_FRAUD); - createCodeValues(CODE_VALUE_PENDING_FRAUD_TAG_ID, pendingFraudTagNames); + createCodeValues(CodeNames.PENDING_FRAUD_TAG.getValue(), pendingFraudTagNames); // pending deceased tag List pendingDeceasedTagNames = new ArrayList<>(); pendingDeceasedTagNames.add(CODE_VALUE_PENDING_DECEASED_TAG_PENDING); pendingDeceasedTagNames.add(CODE_VALUE_PENDING_DECEASED_TAG_DECEASED); - createCodeValues(CODE_VALUE_PENDING_DECEASED_TAG_ID, pendingDeceasedTagNames); + createCodeValues(CodeNames.PENDING_DECEASED_TAG.getValue(), pendingDeceasedTagNames); // hardship tag List hardshipTagNames = new ArrayList<>(); hardshipTagNames.add(CODE_VALUE_HARDSHIP_TAG_ACTIVE); hardshipTagNames.add(CODE_VALUE_HARDSHIP_TAG_INACTIVE); - createCodeValues(CODE_VALUE_HARDSHIP_TAG_ID, hardshipTagNames); + createCodeValues(CodeNames.HARDSHIP_TAG.getValue(), hardshipTagNames); // active duty tag List activeDutyTagNames = new ArrayList<>(); activeDutyTagNames.add(CODE_VALUE_ACTIVE_DUTY_TAG_ACTIVE); activeDutyTagNames.add(CODE_VALUE_ACTIVE_DUTY_TAG_INACTIVE); - createCodeValues(CODE_VALUE_ACTIVE_DUTY_TAG_ID, activeDutyTagNames); + createCodeValues(CodeNames.ACTIVE_DUTY_TAG.getValue(), activeDutyTagNames); // customer identifiers put/post List customerIdentifierNamesPut = new ArrayList<>(); @@ -193,34 +172,34 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep customerIdentifierNamesPut.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_2); customerIdentifierNamesPut.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_3); customerIdentifierNamesPut.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_4); - updateCodeValues(CODE_VALUE_CUSTOMER_IDENTIFIERS_ID, customerIdentifierNamesPut); + updateCodeValues(CodeNames.CUSTOMER_IDENTIFIER.getValue(), customerIdentifierNamesPut); List customerIdentifierNamesPost = new ArrayList<>(); customerIdentifierNamesPost.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_5); customerIdentifierNamesPost.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_6); customerIdentifierNamesPost.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_7); customerIdentifierNamesPost.add(CODE_VALUE_CUSTOMER_IDENTIFIERS_8); - createCodeValues(CODE_VALUE_CUSTOMER_IDENTIFIERS_ID, customerIdentifierNamesPost); + createCodeValues(CodeNames.CUSTOMER_IDENTIFIER.getValue(), customerIdentifierNamesPost); // gender List genderNames = new ArrayList<>(); genderNames.add(CODE_VALUE_GENDER_FEMALE); genderNames.add(CODE_VALUE_GENDER_MALE); - createCodeValues(CODE_VALUE_GENDER_ID, genderNames); + createCodeValues(CodeNames.GENDER.getValue(), genderNames); // client type List clientTypeNames = new ArrayList<>(); clientTypeNames.add(CODE_VALUE_CLIENT_TYPE_CORPORATE); clientTypeNames.add(CODE_VALUE_CLIENT_TYPE_LEGAL); clientTypeNames.add(CODE_VALUE_CLIENT_TYPE_NON_LEGAL); - createCodeValues(CODE_VALUE_CLIENT_TYPE_ID, clientTypeNames); + createCodeValues(CodeNames.CLIENT_TYPE.getValue(), clientTypeNames); // client classification List clientClassificationNames = new ArrayList<>(); clientClassificationNames.add(CODE_VALUE_CLIENT_CLASSIFICATION_LAWYER); clientClassificationNames.add(CODE_VALUE_CLIENT_CLASSIFICATION_DIRECTOR); clientClassificationNames.add(CODE_VALUE_CLIENT_CLASSIFICATION_NONE); - createCodeValues(CODE_VALUE_CLIENT_CLASSIFICATION_ID, clientClassificationNames); + createCodeValues(CodeNames.CLIENT_CLASSIFICATION.getValue(), clientClassificationNames); // add family member - relationship List familyMemberRelationshipNames = new ArrayList<>(); @@ -228,40 +207,51 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep familyMemberRelationshipNames.add(CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_FATHER); familyMemberRelationshipNames.add(CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_MOTHER); familyMemberRelationshipNames.add(CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_CHILD); - createCodeValues(CODE_VALUE_FAMILY_MEMBER_RELATIONSHIP_ID, familyMemberRelationshipNames); + createCodeValues(CodeNames.FAMILY_MEMBER_RELATIONSHIP.getValue(), familyMemberRelationshipNames); // add family member - profession List familyMemberProfessionNames = new ArrayList<>(); familyMemberProfessionNames.add(CODE_VALUE_FAMILY_MEMBER_PROFESSION_EMPLOYEE); familyMemberProfessionNames.add(CODE_VALUE_FAMILY_MEMBER_PROFESSION_SELF_EMPLOYED); - createCodeValues(CODE_VALUE_FAMILY_MEMBER_PROFESSION_ID, familyMemberProfessionNames); + createCodeValues(CodeNames.FAMILY_MEMBER_PROFESSION.getValue(), familyMemberProfessionNames); // add family member - marital status List familyMemberMaritalStatusNames = new ArrayList<>(); familyMemberMaritalStatusNames.add(CODE_VALUE_FAMILY_MARITAL_STATUS_MARRIED); familyMemberMaritalStatusNames.add(CODE_VALUE_FAMILY_MARITAL_STATUS_SINGLE); familyMemberMaritalStatusNames.add(CODE_VALUE_FAMILY_MARITAL_STATUS_WIDOWED); - createCodeValues(CODE_VALUE_FAMILY_MARITAL_STATUS_ID, familyMemberMaritalStatusNames); + createCodeValues(CodeNames.FAMILY_MARITAL_STATUS.getValue(), familyMemberMaritalStatusNames); // add constitution (for client creation as Entity) List constitutionNames = new ArrayList<>(); constitutionNames.add(CODE_VALUE_CONSTITUTION_TEST); - createCodeValues(CODE_VALUE_CONSTITUTION_ID, constitutionNames); + createCodeValues(CodeNames.CONSTITUTION.getValue(), constitutionNames); // add LoanRescheduleReason List rescheduleReasonNames = new ArrayList<>(); rescheduleReasonNames.add(CODE_VALUE_RESCHEDULE_REASON_TEST); - createCodeValues(CODE_VALUE_RESCHEDULE_REASON_ID, rescheduleReasonNames); + createCodeValues(CodeNames.LOAN_RESCHEDULE_REASON.getValue(), rescheduleReasonNames); // add Write-off reasons List 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); + createCodeValues(CodeNames.WRITE_OFF_REASON.getValue(), writeOffReasonNames); + + // Add buy down fee transaction classification + List buydownFeeTransactionClassificationName = new ArrayList<>(); + buydownFeeTransactionClassificationName.add(BUYDOWN_FEE_TRANSACTION_CLASSIFICATION_VALUE); + createCodeValues(CodeNames.BUYDOWN_FEE_TRANSACTION_CLASSIFICATION.getValue(), buydownFeeTransactionClassificationName); + + // Add capitalized income transaction classification + List capitalizedIncomeTransactionClassificationName = new ArrayList<>(); + capitalizedIncomeTransactionClassificationName.add(CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION_VALUE); + createCodeValues(CodeNames.CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION.getValue(), + capitalizedIncomeTransactionClassificationName); } - public void createCodeValues(Long codeId, List codeValueNames) { + public void createCodeValues(String codeName, List codeValueNames) { codeValueNames.forEach(name -> { Integer position = codeValueNames.indexOf(name); PostCodeValuesDataRequest postCodeValuesDataRequest = new PostCodeValuesDataRequest(); @@ -270,7 +260,7 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep postCodeValuesDataRequest.position(position); try { - executeVoid(() -> fineractClient.codeValues().createCodeValue(codeId, postCodeValuesDataRequest, Map.of())); + executeVoid(() -> fineractClient.codeValues().createCodeValue1(codeName, postCodeValuesDataRequest, Map.of())); log.debug("Code value '{}' created successfully", name); } catch (CallFailedRuntimeException e) { if (e.getStatus() == 403 && e.getDeveloperMessage() != null && e.getDeveloperMessage().contains("already exists")) { @@ -282,7 +272,7 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep }); } - public void updateCodeValues(Long codeId, List codeValueNames) { + public void updateCodeValues(String codeName, List codeValueNames) { codeValueNames.forEach(name -> { int position = codeValueNames.indexOf(name) + 1; PutCodeValuesDataRequest putCodeValuesDataRequest = new PutCodeValuesDataRequest(); @@ -290,19 +280,19 @@ public class CodeGlobalInitializerStep implements FineractGlobalInitializerStep putCodeValuesDataRequest.name(name); putCodeValuesDataRequest.position(position); - executeVoid(() -> fineractClient.codeValues().updateCodeValue(codeId, (long) position, putCodeValuesDataRequest, Map.of())); + executeVoid(() -> fineractClient.codeValues().updateCodeValue1(codeName, (long) position, putCodeValuesDataRequest, Map.of())); }); } private void createCodeNames() { List codesNameList = new ArrayList<>(); - codesNameList.add(CODE_NAME_FINANCIAL_INSTRUMENT); - codesNameList.add(CODE_NAME_TRANSACTION_TYPE); - codesNameList.add(CODE_NAME_BANKRUPTCY_TAG); - codesNameList.add(CODE_NAME_PENDING_FRAUD_TAG); - codesNameList.add(CODE_NAME_PENDING_DECEASED_TAG); - codesNameList.add(CODE_NAME_HARDSHIP_TAG); - codesNameList.add(CODE_NAME_ACTIVE_DUTY_TAG); + codesNameList.add(CodeNames.FINANCIAL_INSTRUMENT.getValue()); + codesNameList.add(CodeNames.TRANSACTION_TYPE.getValue()); + codesNameList.add(CodeNames.BANKRUPTCY_TAG.getValue()); + codesNameList.add(CodeNames.PENDING_FRAUD_TAG.getValue()); + codesNameList.add(CodeNames.PENDING_DECEASED_TAG.getValue()); + codesNameList.add(CodeNames.HARDSHIP_TAG.getValue()); + codesNameList.add(CodeNames.ACTIVE_DUTY_TAG.getValue()); codesNameList.forEach(codeName -> { try { diff --git a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java index 233e27215..840b409a6 100644 --- a/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java +++ b/fineract-e2e-tests-runner/src/test/java/org/apache/fineract/test/initializer/global/LoanProductGlobalInitializerStep.java @@ -62,6 +62,7 @@ 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.CodeNames; import org.apache.fineract.test.data.codevalue.CodeValue; import org.apache.fineract.test.data.codevalue.CodeValueResolver; import org.apache.fineract.test.data.codevalue.DefaultCodeValue; @@ -3697,7 +3698,9 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ List buydownfeeClassificationToIncomeAccountMappings = new ArrayList<>(); PostClassificationToIncomeAccountMappings classificationToIncomeAccountMappings = new PostClassificationToIncomeAccountMappings(); - classificationToIncomeAccountMappings.setClassificationCodeValueId(25L); + long classificationId = codeValueResolver.resolve(CodeNames.BUYDOWN_FEE_TRANSACTION_CLASSIFICATION.getValue(), + CodeGlobalInitializerStep.BUYDOWN_FEE_TRANSACTION_CLASSIFICATION_VALUE); + classificationToIncomeAccountMappings.setClassificationCodeValueId(classificationId); classificationToIncomeAccountMappings.setIncomeAccountId(10L); buydownfeeClassificationToIncomeAccountMappings.add(classificationToIncomeAccountMappings); @@ -3736,7 +3739,10 @@ public class LoanProductGlobalInitializerStep implements FineractGlobalInitializ List capitalizedIncomeClassificationToIncomeAccountMappings = new ArrayList<>(); PostClassificationToIncomeAccountMappings classificationToIncomeAccountMappingsCapitalizedIncome = new PostClassificationToIncomeAccountMappings(); - classificationToIncomeAccountMappingsCapitalizedIncome.setClassificationCodeValueId(24L); + long capitalizedIncomeClassificationId = codeValueResolver.resolve( + CodeNames.CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION.getValue(), + CodeGlobalInitializerStep.CAPITALIZED_INCOME_TRANSACTION_CLASSIFICATION_VALUE); + classificationToIncomeAccountMappingsCapitalizedIncome.setClassificationCodeValueId(capitalizedIncomeClassificationId); classificationToIncomeAccountMappingsCapitalizedIncome.setIncomeAccountId(15L); capitalizedIncomeClassificationToIncomeAccountMappings.add(classificationToIncomeAccountMappingsCapitalizedIncome); diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature index c300e33bc..161024f8f 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanBuyDownFees.feature @@ -3232,7 +3232,7 @@ Feature:Feature: Buy Down Fees And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount Then Loan status will be "ACTIVE" - When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "buydown_fee_transaction_classification" classification + When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "buydown_fee_transaction_classification_value" classification Then Loan Repayment schedule has 3 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 | | | | @@ -3841,7 +3841,7 @@ Feature:Feature: Buy Down Fees | LP2_PROGRESSIVE_ADVANCED_PAYMENT_ALLOCATION_BUYDOWN_FEES_CLASSIFICATION_INCOME_MAP | 01 January 2024 | 350 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "01 January 2024" with "350" amount and expected disbursement date on "01 January 2024" And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount - And Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and classification: pending_bankruptcy + When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "buydown_fee_transaction_classification_value" classification And Admin sets the business date to "02 January 2024" And Admin runs inline COB job for Loan Then Loan Transactions tab has a "BUY_DOWN_FEE" transaction with date "01 January 2024" which has the following Journal entries: @@ -3868,7 +3868,7 @@ Feature:Feature: Buy Down Fees And Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount And Admin sets the business date to "02 January 2024" And Admin runs inline COB job for Loan - And Admin adds buy down fee with "AUTOPAY" payment type to the loan on "02 January 2024" with "20" EUR transaction amount and classification: pending_bankruptcy + When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "02 January 2024" with "20" EUR transaction amount and "buydown_fee_transaction_classification_value" classification And Admin sets the business date to "03 January 2024" And Admin runs inline COB job for Loan Then Loan Transactions tab has a "BUY_DOWN_FEE" transaction with date "01 January 2024" which has the following Journal entries: @@ -3902,7 +3902,7 @@ Feature:Feature: Buy Down Fees And Admin successfully approves the loan on "01 January 2024" with "100" amount and expected disbursement date on "01 January 2024" And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount Then Loan status will be "ACTIVE" - When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and classification: pending_bankruptcy + When Admin adds buy down fee with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "buydown_fee_transaction_classification_value" classification Then Loan Repayment schedule has 3 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 | | | | @@ -3920,7 +3920,7 @@ Feature:Feature: Buy Down Fees | Type | Account code | Account name | Debit | Credit | | EXPENSE | 450280 | Buy Down Expense | 50.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 50.0 | - And Loan Transactions tab has a "Buy Down Fee" transaction with date "01 January 2024" which has classification code value "pending_bankruptcy" + And Loan Transactions tab has a "Buy Down Fee" transaction with date "01 January 2024" which has classification code value "buydown_fee_transaction_classification_value" And Buy down fee contains the following data: | Date | Fee Amount | Amortized Amount | Not Yet Amortized Amount | Adjusted Amount | Charged Off Amount | | 01 January 2024 | 50.0 | 0.0 | 50.0 | 0.0 | 0.0 | diff --git a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature index 5a6896172..9857723ed 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanCapitalizedIncome.feature @@ -7673,7 +7673,7 @@ Feature: Capitalized Income And Admin successfully disburse the loan on "1 January 2024" with "900" EUR transaction amount Then Loan status will be "ACTIVE" When Admin sets the business date to "2 January 2024" - And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "2 January 2024" with "100" EUR transaction amount and "capitalized_income_transaction_classification" classification + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "2 January 2024" with "100" EUR transaction amount and "capitalized_income_transaction_classification_value" classification Then Loan Repayment schedule has 2 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 | | 900.0 | | | 0.0 | | 0.0 | 0.0 | | | | @@ -8277,7 +8277,7 @@ Feature: Capitalized Income Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4096 - Scenario: Verify GL entries for Capitalized Income Amortization - UC2: Amortization for Capitalized Income with classification rule: pending_bankruptcy + Scenario: Verify GL entries for Capitalized Income Amortization - UC2: Amortization for Capitalized Income with classification rule: capitalized_income_transaction_classification_value When Admin sets the business date to "01 January 2024" And Admin creates a client with random data When Admin creates a fully customized loan with the following data: @@ -8285,7 +8285,7 @@ Feature: Capitalized Income | LP2_PROGRESSIVE_ADV_PMNT_ALLOCATION_CAPITALIZED_INCOME_ADJ_CUSTOM_ALLOC_CLASSIFICATION_INCOME_MAP | 01 January 2024 | 350 | 7 | DECLINING_BALANCE | DAILY | EQUAL_INSTALLMENTS | 3 | MONTHS | 1 | MONTHS | 3 | 0 | 0 | 0 | ADVANCED_PAYMENT_ALLOCATION | And Admin successfully approves the loan on "01 January 2024" with "350" amount and expected disbursement date on "01 January 2024" And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount - And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and classification: scheduled_payment + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "capitalized_income_transaction_classification_value" classification When Admin sets the business date to "02 January 2024" And Admin runs inline COB job for Loan Then Loan Transactions tab has a "CAPITALIZED_INCOME" transaction with date "01 January 2024" which has the following Journal entries: @@ -8301,7 +8301,7 @@ Feature: Capitalized Income Then Loan is closed with zero outstanding balance and it's all installments have obligations met @TestRailId:C4097 - Scenario: Verify GL entries for Capitalized Income Amortization - UC3: Amortization for Capitalized Incomes with NO classification and with classification rule: pending_bankruptcy + Scenario: Verify GL entries for Capitalized Income Amortization - UC3: Amortization for Capitalized Incomes with NO classification and with classification rule: capitalized_income_transaction_classification_value When Admin sets the business date to "01 January 2024" And Admin creates a client with random data When Admin creates a fully customized loan with the following data: @@ -8312,7 +8312,7 @@ Feature: Capitalized Income And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount When Admin sets the business date to "02 January 2024" And Admin runs inline COB job for Loan - And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "02 January 2024" with "20" EUR transaction amount and classification: scheduled_payment + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "02 January 2024" with "20" EUR transaction amount and "capitalized_income_transaction_classification_value" classification When Admin sets the business date to "03 January 2024" And Admin runs inline COB job for Loan Then Loan Transactions tab has a "CAPITALIZED_INCOME" transaction with date "01 January 2024" which has the following Journal entries: @@ -8346,7 +8346,7 @@ Feature: Capitalized Income And Admin successfully approves the loan on "01 January 2024" with "200" amount and expected disbursement date on "01 January 2024" And Admin successfully disburse the loan on "01 January 2024" with "100" EUR transaction amount Then Loan status will be "ACTIVE" - And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and classification: scheduled_payment + And Admin adds capitalized income with "AUTOPAY" payment type to the loan on "01 January 2024" with "50" EUR transaction amount and "capitalized_income_transaction_classification_value" classification Then Loan Repayment schedule has 3 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 | | | | @@ -8365,7 +8365,7 @@ Feature: Capitalized Income | Type | Account code | Account name | Debit | Credit | | ASSET | 112601 | Loans Receivable | 50.0 | | | LIABILITY | 145024 | Deferred Capitalized Income | | 50.0 | - And Loan Transactions tab has a "Capitalized Income" transaction with date "01 January 2024" which has classification code value "scheduled_payment" + And Loan Transactions tab has a "Capitalized Income" transaction with date "01 January 2024" which has classification code value "capitalized_income_transaction_classification_value" Then LoanCapitalizedIncomeTransactionCreatedBusinessEvent is raised on "01 January 2024" And Admin adds capitalized income adjustment with "AUTOPAY" payment type to the loan on "01 January 2024" with "25" EUR transaction amount Then Loan Transactions tab has the following data: 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 4808c43a3..5938f70d7 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature @@ -187,26 +187,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 5 options, with the following data: + Then Loan Product Charge-Off reasons options from loan product template have 3 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 | + | Fraud | | 0 | true | false | + | Delinquent | | 1 | true | false | + | Other | | 2 | true | false | @TestRailId:C3482 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 5 options, with the following data: + Then Loan Product "LP1" Charge-Off reasons options from specific loan product have 3 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 | + | Fraud | | 0 | true | false | + | Delinquent | | 1 | true | false | + | Other | | 2 | true | false | @TestRailId:C3587 Scenario: As a user I would like to verify interestRecognitionOnDisbursementDate=false flag in loan product response diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResource.java index 2bb9a318c..6c3ecc774 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodeValuesApiResource.java @@ -41,6 +41,7 @@ import jakarta.ws.rs.core.UriInfo; import java.util.Arrays; import java.util.Collection; import java.util.HashSet; +import java.util.List; import java.util.Set; import lombok.RequiredArgsConstructor; import org.apache.fineract.commands.domain.CommandWrapper; @@ -49,6 +50,7 @@ import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformS import org.apache.fineract.infrastructure.codes.CodeConstants.CodevalueJSONinputParams; import org.apache.fineract.infrastructure.codes.data.CodeData; import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.codes.service.CodeReadPlatformService; import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; import org.apache.fineract.infrastructure.core.data.CommandProcessingResult; @@ -57,7 +59,7 @@ import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSer import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.springframework.stereotype.Component; -@Path("/v1/codes/{codeId}/codevalues") +@Path("/v1/codes") @Component @Tag(name = "Code Values", description = "Code and code values: Codes represent a specific category of data, their code values are a specific instance of that category.\n" + "\n" @@ -76,11 +78,13 @@ public class CodeValuesApiResource { private final PlatformSecurityContext context; private final CodeValueReadPlatformService readPlatformService; + private final CodeReadPlatformService codeReadPlatformService; private final DefaultToApiJsonSerializer toApiJsonSerializer; private final ApiRequestParameterHelper apiRequestParameterHelper; private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService; @GET + @Path("{codeId}/codevalues") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "List Code Values", description = "Returns the list of Code Values for a given Code\n" + "\n" @@ -99,7 +103,7 @@ public class CodeValuesApiResource { } @GET - @Path("{codeValueId}") + @Path("{codeId}/codevalues/{codeValueId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Retrieve a Code description", description = "Returns the details of a Code Value\n" + "\n" + "Example Requests:\n" @@ -119,6 +123,7 @@ public class CodeValuesApiResource { } @POST + @Path("{codeId}/codevalues") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Create a Code description", description = "") @@ -137,7 +142,7 @@ public class CodeValuesApiResource { } @PUT - @Path("{codeValueId}") + @Path("{codeId}/codevalues/{codeValueId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Update a Code description", description = "Updates the details of a code description.") @@ -157,7 +162,7 @@ public class CodeValuesApiResource { } @DELETE - @Path("{codeValueId}") + @Path("{codeId}/codevalues/{codeValueId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Operation(summary = "Delete a Code description", description = "Deletes a code description") @@ -172,4 +177,89 @@ public class CodeValuesApiResource { return this.toApiJsonSerializer.serialize(result); } + + @GET + @Path("name/{codeName}/codevalues") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "List Code Values", description = "Returns the list of Code Values for a given Code\n" + "\n" + + "Example Requests:\n" + "\n" + "codes/1/codevalues", parameters = @Parameter(name = "codeId", description = "co")) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "A List of code values for a given code", content = @Content(array = @ArraySchema(schema = @Schema(implementation = CodeValuesApiResourceSwagger.GetCodeValuesDataResponse.class)))) }) + public List retrieveAllCodeValues(@Context final UriInfo uriInfo, + @PathParam("codeName") @Parameter(description = "codeName") final String codeName) { + + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + + return this.readPlatformService.retrieveAllCodeValues(codeName); + } + + @GET + @Path("name/{codeName}/codevalues/{codeValueId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Retrieve a Code description", description = "Returns the details of a Code Value\n" + "\n" + "Example Requests:\n" + + "\n" + "codes/name/ADDRESS_TYPE/codevalues/1") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.GetCodeValuesDataResponse.class))) }) + public CodeValueData retrieveCodeValue(@Context final UriInfo uriInfo, + @PathParam("codeName") @Parameter(description = "codeName") final String codeName, + @PathParam("codeValueId") @Parameter(description = "codeValueId") final Long codeValueId) { + + this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS); + + return this.readPlatformService.retrieveCodeValue(codeName, codeValueId); + } + + @POST + @Path("name/{codeName}/codevalues") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Create a Code description", description = "") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.PostCodeValuesDataRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.PostCodeValueDataResponse.class))) }) + public CommandProcessingResult createCodeValue(@PathParam("codeName") @Parameter(description = "codeName") final String codeName, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + CodeData code = codeReadPlatformService.retrieveCode(codeName); + final CommandWrapper commandRequest = new CommandWrapperBuilder().createCodeValue(code.getId(), codeName) + .withJson(apiRequestBodyAsJson).build(); + + return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } + + @PUT + @Path("name/{codeName}/codevalues/{codeValueId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Update a Code description", description = "Updates the details of a code description.") + @RequestBody(required = true, content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.PutCodeValuesDataRequest.class))) + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.PutCodeValueDataResponse.class))) }) + public CommandProcessingResult updateCodeValue(@PathParam("codeName") @Parameter(description = "codeName") final String codeName, + @PathParam("codeValueId") @Parameter(description = "codeValueId") final Long codeValueId, + @Parameter(hidden = true) final String apiRequestBodyAsJson) { + + CodeData code = codeReadPlatformService.retrieveCode(codeName); + final CommandWrapper commandRequest = new CommandWrapperBuilder().updateCodeValue(codeName, code.getId(), codeValueId) + .withJson(apiRequestBodyAsJson).build(); + + return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } + + @DELETE + @Path("name/{codeName}/codevalues/{codeValueId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Operation(summary = "Delete a Code description", description = "Deletes a code description") + @ApiResponses({ + @ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = CodeValuesApiResourceSwagger.DeleteCodeValueDataResponse.class))) }) + public CommandProcessingResult deleteCodeValue(@PathParam("codeName") @Parameter(description = "codeName") final String codeName, + @PathParam("codeValueId") @Parameter(description = "codeValueId") final Long codeValueId) { + + CodeData code = codeReadPlatformService.retrieveCode(codeName); + final CommandWrapper commandRequest = new CommandWrapperBuilder().deleteCodeValue(codeName, code.getId(), codeValueId).build(); + + return this.commandsSourceWritePlatformService.logCommandSource(commandRequest); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodesApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodesApiResource.java index 409bf3bf1..0f275432d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodesApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/api/CodesApiResource.java @@ -134,7 +134,7 @@ public class CodesApiResource { public String retrieveCodeByName(@PathParam("codeName") @Parameter(description = "codeName") final String codeName, @Context final UriInfo uriInfo) { - final CodeData code = this.readPlatformService.retriveCode(codeName); + final CodeData code = this.readPlatformService.retrieveCode(codeName); final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters()); return this.toApiJsonSerializer.serialize(settings, code, RESPONSE_DATA_PARAMETERS); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformServiceImpl.java index 819171032..5f9970f2b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeReadPlatformServiceImpl.java @@ -86,7 +86,7 @@ public class CodeReadPlatformServiceImpl implements CodeReadPlatformService { } @Override - public CodeData retriveCode(final String codeName) { + public CodeData retrieveCode(final String codeName) { try { this.context.authenticatedUser(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformServiceImpl.java index 23a2e1306..f4f8957c0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/codes/service/CodeValueReadPlatformServiceImpl.java @@ -22,10 +22,12 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; import java.util.List; +import lombok.RequiredArgsConstructor; import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository; import org.apache.fineract.infrastructure.codes.exception.CodeValueNotFoundException; +import org.apache.fineract.infrastructure.codes.mapper.CodeValueMapper; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.cache.annotation.Cacheable; import org.springframework.dao.EmptyResultDataAccessException; import org.springframework.jdbc.core.JdbcTemplate; @@ -33,16 +35,13 @@ import org.springframework.jdbc.core.RowMapper; import org.springframework.stereotype.Service; @Service +@RequiredArgsConstructor public class CodeValueReadPlatformServiceImpl implements CodeValueReadPlatformService { private final JdbcTemplate jdbcTemplate; private final PlatformSecurityContext context; - - @Autowired - public CodeValueReadPlatformServiceImpl(final PlatformSecurityContext context, final JdbcTemplate jdbcTemplate) { - this.context = context; - this.jdbcTemplate = jdbcTemplate; - } + private final CodeValueRepository codeValueRepository; + private final CodeValueMapper codeValueMapper; private static final class CodeValueDataMapper implements RowMapper { @@ -105,4 +104,22 @@ public class CodeValueReadPlatformServiceImpl implements CodeValueReadPlatformSe } } + + @Override + public List retrieveAllCodeValues(String codeName) { + // TODO: review whether it is needed. + this.context.authenticatedUser(); + return codeValueMapper.map(codeValueRepository.findByCodeName(codeName)); + } + + @Override + public CodeValueData retrieveCodeValue(String codeName, Long codeValueId) { + // TODO: review whether it is needed. + this.context.authenticatedUser(); + CodeValueData codeValueData = codeValueMapper.map(codeValueRepository.findByCodeNameAndId(codeName, codeValueId)); + if (codeValueData == null) { + throw new CodeValueNotFoundException(codeName, codeValueId); + } + return codeValueData; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableWriteServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableWriteServiceImpl.java index 018f3cb4d..ae4c0db88 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableWriteServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/dataqueries/service/DatatableWriteServiceImpl.java @@ -689,7 +689,7 @@ public class DatatableWriteServiceImpl implements DatatableWriteService { if (StringUtils.isNotBlank(code)) { if (isConstraintApproach) { - codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retriveCode(code).getId()); + codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retrieveCode(code).getId()); String fkName = "fk_" + dataTableNameAlias + "_" + name; constrainBuilder.append(", CONSTRAINT ").append(sqlGenerator.escape(fkName)).append(" ").append("FOREIGN KEY (") .append(sqlGenerator.escape(name)).append(") ").append(REFERENCES_CLAUSE) @@ -753,7 +753,7 @@ public class DatatableWriteServiceImpl implements DatatableWriteService { if (StringUtils.isNotBlank(code)) { if (isConstraintApproach) { String fkName = "fk_" + dataTableNameAlias + "_" + name; - codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retriveCode(code).getId()); + codeMappings.put(dataTableNameAlias + "_" + name, this.codeReadPlatformService.retrieveCode(code).getId()); constrainBuilder.append(",ADD CONSTRAINT ").append(sqlGenerator.escape(fkName)).append(" ").append("FOREIGN KEY (") .append(sqlGenerator.escape(name)).append(") ").append(REFERENCES_CLAUSE) .append(sqlGenerator.escape(CODE_VALUES_TABLE)).append(" (").append(TABLE_FIELD_ID).append(")"); @@ -823,7 +823,7 @@ public class DatatableWriteServiceImpl implements DatatableWriteService { } } if (newCode != null) { - codeMappings.put(dataTableNameAlias + "_" + newName, this.codeReadPlatformService.retriveCode(newCode).getId()); + codeMappings.put(dataTableNameAlias + "_" + newName, this.codeReadPlatformService.retrieveCode(newCode).getId()); if (code == null || !StringUtils.equalsIgnoreCase(oldName, newName)) { constrainBuilder.append(", ADD CONSTRAINT ").append(sqlGenerator.escape(newFkName)).append(" ") .append("FOREIGN KEY (").append(sqlGenerator.escape(newName)).append(") ").append(REFERENCES_CLAUSE)