Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1257,6 +1257,14 @@ public CommandWrapperBuilder createCodeValue(final Long codeId) {
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";
Expand All @@ -1266,6 +1274,15 @@ public CommandWrapperBuilder updateCodeValue(final Long codeId, final Long codeV
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";
Expand All @@ -1275,6 +1292,15 @@ public CommandWrapperBuilder deleteCodeValue(final Long codeId, final Long codeV
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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -26,4 +27,6 @@ public interface CodeValueRepository extends JpaRepository<CodeValue, Long>, Jpa
CodeValue findByCodeNameAndId(String codeName, Long id);

CodeValue findByCodeNameAndLabel(String codeName, String label);

List<CodeValue> findByCodeName(String codeName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,5 +27,5 @@ public interface CodeReadPlatformService {

CodeData retrieveCode(Long codeId);

CodeData retriveCode(String codeName);
CodeData retrieveCode(String codeName);
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,8 @@ public interface CodeValueReadPlatformService {
Collection<CodeValueData> retrieveAllCodeValues(Long codeId);

CodeValueData retrieveCodeValue(Long codeValueId);

List<CodeValueData> retrieveAllCodeValues(String codeName);

CodeValueData retrieveCodeValue(String codeName, Long codeValueId);
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<GetCodeValuesDataResponse> 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<GetCodeValuesDataResponse> 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();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,6 @@
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;
Expand All @@ -105,8 +104,6 @@
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;
Expand All @@ -131,6 +128,7 @@
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;
Expand Down Expand Up @@ -4879,14 +4877,6 @@ public void adminAddsCapitalizedIncomeToTheLoanOnWithEURTransactionAmount(final
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) {
Expand All @@ -4904,7 +4894,8 @@ public PostLoansLoanIdTransactionsResponse addCapitalizedIncomeWithClassificatio
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)
Expand Down Expand Up @@ -5373,32 +5364,25 @@ public void adminAddsBuyDownFeesToTheLoanOnWithEURTransactionAmount(final String
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();

final DefaultPaymentType paymentType = DefaultPaymentType.valueOf(transactionPaymentType);
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)
Expand Down Expand Up @@ -5740,27 +5724,18 @@ public void loanTransactionHasClassification(String transactionType, String expe
.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<GetCodeValuesDataResponse> existingCodeValues = fineractClient.codeValues().retrieveAllCodeValues(code.getId());
String codeValueName = classificationName + "_value";

List<GetCodeValuesDataResponse> 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:")
Expand Down
Loading
Loading