From 628f27bf322de146488511ba3fc69d1a4631a2b6 Mon Sep 17 00:00:00 2001 From: Oleksii Novikov Date: Tue, 12 Nov 2024 11:54:18 +0200 Subject: [PATCH] FINERACT-1806: Add charge-off reasons to loan product response --- .../service/CodeValueReadPlatformService.java | 3 +- .../fineract/test/api/ApiConfiguration.java | 6 ++ .../test/helper/ErrorMessageHelper.java | 16 ++++ .../stepdef/loan/LoanProductsCustomApi.java | 30 +++++++ .../test/stepdef/loan/LoanStepDef.java | 90 +++++++++++++++++++ .../resources/features/LoanProduct.feature | 18 ++++ .../api/LoanProductsApiResourceSwagger.java | 20 +++++ .../loanproduct/data/LoanProductData.java | 7 +- ...ulkImportWorkbookPopulatorServiceImpl.java | 2 +- .../CodeValueReadPlatformServiceImpl.java | 3 +- .../api/LoanProductsApiResource.java | 7 +- 11 files changed, 197 insertions(+), 5 deletions(-) create mode 100644 fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanProductsCustomApi.java 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 d1e508bc4..f56a9ddc8 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 @@ -19,6 +19,7 @@ package org.apache.fineract.infrastructure.codes.service; import java.util.Collection; +import java.util.List; import org.apache.fineract.infrastructure.codes.data.CodeValueData; /** @@ -40,7 +41,7 @@ import org.apache.fineract.infrastructure.codes.data.CodeValueData; */ public interface CodeValueReadPlatformService { - Collection retrieveCodeValuesByCode(String code); + List retrieveCodeValuesByCode(String code); Collection retrieveAllCodeValues(Long codeId); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/api/ApiConfiguration.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/api/ApiConfiguration.java index 9fd37335a..768b9166c 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/api/ApiConfiguration.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/api/ApiConfiguration.java @@ -53,6 +53,7 @@ import org.apache.fineract.client.services.SchedulerApi; import org.apache.fineract.client.services.SchedulerJobApi; import org.apache.fineract.client.services.UsersApi; import org.apache.fineract.client.util.FineractClient; +import org.apache.fineract.test.stepdef.loan.LoanProductsCustomApi; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -98,6 +99,11 @@ public class ApiConfiguration { return fineractClient.createService(LoanProductsApi.class); } + @Bean + public LoanProductsCustomApi loanProductsCustomApi() { + return fineractClient.createService(LoanProductsCustomApi.class); + } + @Bean public SavingsProductApi savingsProductApi() { return fineractClient.createService(SavingsProductApi.class); diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java index 09b640610..03000bbea 100644 --- a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/helper/ErrorMessageHelper.java @@ -24,6 +24,7 @@ import java.time.LocalDate; import java.time.format.DateTimeFormatter; import java.util.List; import java.util.Map; +import java.util.stream.Collectors; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.client.models.BatchResponse; import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse; @@ -888,4 +889,19 @@ public final class ErrorMessageHelper { public static String downpaymentDisabledOnProductErrorCodeMsg() { return "The Loan can not override the downpayment properties because in the Loan Product the downpayment is disabled"; } + + public static String wrongValueInLineInChargeOffReasonOptions(final int line, final List> actual, + final List expected) { + final String actualValues = actual.stream().map(List::toString).collect(Collectors.joining(System.lineSeparator())); + + return String.format( + "%nWrong value in Loan Charge-Off Reason Options line %s. %nActual values in line: %s %nExpected values in line: %s", line, + actualValues, expected); + } + + public static String wrongNumberOfLinesInChargeOffReasonOptions(final int actual, final int expected) { + return String.format( + "Number of lines in loan charge-off reason options is not correct. Actual value is: %d - Expected value is: %d", actual, + expected); + } } diff --git a/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanProductsCustomApi.java b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanProductsCustomApi.java new file mode 100644 index 000000000..6fd53a274 --- /dev/null +++ b/fineract-e2e-tests-core/src/test/java/org/apache/fineract/test/stepdef/loan/LoanProductsCustomApi.java @@ -0,0 +1,30 @@ +/** + * 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.stepdef.loan; + +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import retrofit2.Call; +import retrofit2.http.GET; + +public interface LoanProductsCustomApi { + + @GET("v1/loanproducts/{productId}") + Call retrieveLoanProductDetails(@retrofit2.http.Path("productId") Long productId, + @retrofit2.http.Query("template") String isTemplate); +} 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 5e1b2b783..6481dfb0a 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 @@ -52,7 +52,9 @@ import org.apache.fineract.avro.loan.v1.LoanStatusEnumDataV1; import org.apache.fineract.avro.loan.v1.LoanTransactionDataV1; import org.apache.fineract.client.models.AdvancedPaymentData; import org.apache.fineract.client.models.DeleteLoansLoanIdResponse; +import org.apache.fineract.client.models.GetLoanProductsChargeOffReasonOptions; import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import org.apache.fineract.client.models.GetLoanProductsTemplateResponse; import org.apache.fineract.client.models.GetLoansLoanIdDelinquencySummary; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargeData; import org.apache.fineract.client.models.GetLoansLoanIdLoanChargePaidByData; @@ -158,6 +160,9 @@ public class LoanStepDef extends AbstractStepDef { @Autowired private LoanProductsApi loanProductsApi; + @Autowired + private LoanProductsCustomApi loanProductsCustomApi; + @Autowired private EventStore eventStore; @@ -2550,6 +2555,66 @@ public class LoanStepDef extends AbstractStepDef { assertTrue(relationshipOptional.isPresent(), "Missed relationship between transactions"); } + @Then("Loan Product Charge-Off reasons options from loan product template have {int} options, with the following data:") + public void loanProductTemplateChargeOffReasonOptionsCheck(final int linesExpected, final DataTable table) throws IOException { + final Response loanProductDetails = loanProductsApi.retrieveTemplate11(false).execute(); + ErrorHelper.checkSuccessfulApiCall(loanProductDetails); + + assertNotNull(loanProductDetails.body()); + final List chargeOffReasonOptions = loanProductDetails.body().getChargeOffReasonOptions(); + assertNotNull(chargeOffReasonOptions); + + final List> data = table.asLists(); + final int linesActual = chargeOffReasonOptions.size(); + data.stream().skip(1) // skip headers + .forEach(expectedValues -> { + final List> actualValuesList = chargeOffReasonOptions.stream() + .map(chargeOffReason -> fetchValuesOfLoanChargeOffReasonOptions(data.get(0), chargeOffReason)) + .collect(Collectors.toList()); + + final boolean containsExpectedValues = actualValuesList.stream() + .anyMatch(actualValues -> actualValues.equals(expectedValues)); + assertThat(containsExpectedValues).as(ErrorMessageHelper + .wrongValueInLineInChargeOffReasonOptions(data.indexOf(expectedValues), actualValuesList, expectedValues)) + .isTrue(); + + assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInChargeOffReasonOptions(linesActual, linesExpected)) + .isEqualTo(linesExpected); + }); + } + + @Then("Loan Product {string} Charge-Off reasons options from specific loan product have {int} options, with the following data:") + public void specificLoanProductChargeOffReasonOptionsCheck(final String loanProductName, final int linesExpected, final DataTable table) + throws IOException { + final DefaultLoanProduct product = DefaultLoanProduct.valueOf(loanProductName); + final Long loanProductId = loanProductResolver.resolve(product); + final Response loanProductDetails = loanProductsCustomApi + .retrieveLoanProductDetails(loanProductId, "true").execute(); + ErrorHelper.checkSuccessfulApiCall(loanProductDetails); + + assertNotNull(loanProductDetails.body()); + final List chargeOffReasonOptions = loanProductDetails.body().getChargeOffReasonOptions(); + assertNotNull(chargeOffReasonOptions); + + final List> data = table.asLists(); + final int linesActual = chargeOffReasonOptions.size(); + data.stream().skip(1) // skip headers + .forEach(expectedValues -> { + final List> actualValuesList = chargeOffReasonOptions.stream() + .map(chargeOffReason -> fetchValuesOfLoanChargeOffReasonOptions(data.get(0), chargeOffReason)) + .collect(Collectors.toList()); + + final boolean containsExpectedValues = actualValuesList.stream() + .anyMatch(actualValues -> actualValues.equals(expectedValues)); + assertThat(containsExpectedValues).as(ErrorMessageHelper + .wrongValueInLineInChargeOffReasonOptions(data.indexOf(expectedValues), actualValuesList, expectedValues)) + .isTrue(); + + assertThat(linesActual).as(ErrorMessageHelper.wrongNumberOfLinesInChargeOffReasonOptions(linesActual, linesExpected)) + .isEqualTo(linesExpected); + }); + } + private void createCustomizedLoan(final List loanData, final boolean withEmi) throws IOException { final String loanProduct = loanData.get(0); final String submitDate = loanData.get(1); @@ -2928,4 +2993,29 @@ public class LoanStepDef extends AbstractStepDef { } return actualValues; } + + @SuppressFBWarnings("SF_SWITCH_NO_DEFAULT") + private List fetchValuesOfLoanChargeOffReasonOptions(final List header, + final GetLoanProductsChargeOffReasonOptions chargeOffReasonOption) { + final List actualValues = new ArrayList<>(); + for (String headerName : header) { + switch (headerName) { + case "Charge-Off Reason Name" -> + actualValues.add(chargeOffReasonOption.getName() == null ? null : chargeOffReasonOption.getName()); + case "Description" -> { + assertNotNull(chargeOffReasonOption.getDescription()); + actualValues + .add(chargeOffReasonOption.getDescription().isEmpty() || chargeOffReasonOption.getDescription() == null ? null + : chargeOffReasonOption.getDescription()); + } + case "Position" -> actualValues + .add(chargeOffReasonOption.getPosition() == null ? null : String.valueOf(chargeOffReasonOption.getPosition())); + case "Is Active" -> + actualValues.add(chargeOffReasonOption.getActive() == null ? null : String.valueOf(chargeOffReasonOption.getActive())); + case "Is Mandatory" -> actualValues + .add(chargeOffReasonOption.getMandatory() == null ? null : String.valueOf(chargeOffReasonOption.getMandatory())); + } + } + return actualValues; + } } 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 271f79471..c58cfc481 100644 --- a/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature +++ b/fineract-e2e-tests-runner/src/test/resources/features/LoanProduct.feature @@ -181,3 +181,21 @@ Feature: LoanProduct Then Loan has 500 outstanding amount When Refund undo happens on "1 July 2022" Then Loan has 1000 outstanding amount + + Scenario: As a user I would like to verify Charge-Off reasons options in loan product template 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 Charge-Off reasons options from loan product template have 2 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 | + + 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 2 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 | \ No newline at end of file diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index cd04ef8e8..5ecfb6cff 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -1016,6 +1016,24 @@ final class LoanProductsApiResourceSwagger { public String description; } + static final class GetLoanProductsChargeOffReasonOptions { + + private GetLoanProductsChargeOffReasonOptions() {} + + @Schema(example = "2") + public Long id; + @Schema(example = "debit_card") + public String name; + @Schema(example = "2") + public Integer position; + @Schema(example = "Charge-Off reason description") + public String description; + @Schema(example = "true") + public Boolean active; + @Schema(example = "false") + public Boolean mandatory; + } + @Schema(example = "false") public Boolean includeInBorrowerCycle; @Schema(example = "false") @@ -1068,6 +1086,7 @@ final class LoanProductsApiResourceSwagger { public List supportedInterestRefundTypes; public List supportedInterestRefundTypesOptions; + public List chargeOffReasonOptions; } @Schema(description = "GetLoanProductsProductIdResponse") @@ -1342,6 +1361,7 @@ final class LoanProductsApiResourceSwagger { @Schema(example = "false") public Boolean enableAccrualActivityPosting; public List supportedInterestRefundTypes; + public List chargeOffReasonOptions; } @Schema(description = "PutLoanProductsProductIdRequest") diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java index f1c232985..c32997cb6 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanproduct/data/LoanProductData.java @@ -32,6 +32,7 @@ import org.apache.fineract.accounting.common.AccountingRuleType; import org.apache.fineract.accounting.glaccount.data.GLAccountData; import org.apache.fineract.accounting.producttoaccountmapping.data.ChargeToGLAccountMapper; import org.apache.fineract.accounting.producttoaccountmapping.data.PaymentTypeToGLAccountMapper; +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.organisation.monetary.data.CurrencyData; @@ -212,6 +213,8 @@ public class LoanProductData implements Serializable { private final boolean isEqualAmortization; private final BigDecimal fixedPrincipalPercentagePerInstallment; + private final List chargeOffReasonOptions; + // Delinquency Buckets private final Collection delinquencyBucketOptions; private final DelinquencyBucketData delinquencyBucket; @@ -913,6 +916,7 @@ public class LoanProductData implements Serializable { this.enableAccrualActivityPosting = enableAccrualActivityPosting; this.supportedInterestRefundTypes = supportedInterestRefundTypes; this.supportedInterestRefundTypesOptions = null; + this.chargeOffReasonOptions = null; } public LoanProductData(final LoanProductData productData, final Collection chargeOptions, @@ -935,7 +939,7 @@ public class LoanProductData implements Serializable { final List advancedPaymentAllocationTypes, final List loanScheduleTypeOptions, final List loanScheduleProcessingTypeOptions, final List creditAllocationTransactionTypes, final List creditAllocationAllocationTypes, - final List supportedInterestRefundTypesOptions) { + final List supportedInterestRefundTypesOptions, final List chargeOffReasonOptions) { this.id = productData.id; this.name = productData.name; @@ -1092,6 +1096,7 @@ public class LoanProductData implements Serializable { this.enableAccrualActivityPosting = productData.enableAccrualActivityPosting; this.supportedInterestRefundTypesOptions = supportedInterestRefundTypesOptions; this.supportedInterestRefundTypes = productData.supportedInterestRefundTypes; + this.chargeOffReasonOptions = chargeOffReasonOptions; } private Collection nullIfEmpty(final Collection charges) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java index 353f56a1c..4774daf5c 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/bulkimport/service/BulkImportWorkbookPopulatorServiceImpl.java @@ -300,7 +300,7 @@ public class BulkImportWorkbookPopulatorServiceImpl implements BulkImportWorkboo private List fetchCodeValuesByCodeName(String codeName) { List codeValues = null; if (codeName != null) { - codeValues = (List) codeValueReadPlatformService.retrieveCodeValuesByCode(codeName); + codeValues = codeValueReadPlatformService.retrieveCodeValuesByCode(codeName); } else { throw new NullPointerException(); } 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 7821aa062..23a2e1306 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 @@ -21,6 +21,7 @@ package org.apache.fineract.infrastructure.codes.service; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collection; +import java.util.List; import org.apache.fineract.infrastructure.codes.data.CodeValueData; import org.apache.fineract.infrastructure.codes.exception.CodeValueNotFoundException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; @@ -66,7 +67,7 @@ public class CodeValueReadPlatformServiceImpl implements CodeValueReadPlatformSe @Override @Cacheable(value = "code_values", key = "T(org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil).getTenant().getTenantIdentifier().concat(#code+'cv')") - public Collection retrieveCodeValuesByCode(final String code) { + public List retrieveCodeValuesByCode(final String code) { this.context.authenticatedUser(); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java index 75d16770b..7adcbdefd 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResource.java @@ -54,6 +54,8 @@ import org.apache.fineract.accounting.producttoaccountmapping.service.ProductToG import org.apache.fineract.commands.domain.CommandWrapper; import org.apache.fineract.commands.service.CommandWrapperBuilder; import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; +import org.apache.fineract.infrastructure.codes.data.CodeValueData; +import org.apache.fineract.infrastructure.codes.service.CodeValueReadPlatformService; import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.api.ApiParameterHelper; import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper; @@ -150,6 +152,7 @@ public class LoanProductsApiResource { private final RateReadService rateReadService; private final ConfigurationDomainService configurationDomainService; private final DelinquencyReadPlatformService delinquencyReadPlatformService; + private final CodeValueReadPlatformService codeValueReadPlatformService; @POST @Consumes({ MediaType.APPLICATION_JSON }) @@ -425,6 +428,8 @@ public class LoanProductsApiResource { final List creditAllocationAllocationTypes = AllocationType.getValuesAsEnumOptionDataList(); final List supportedInterestRefundTypesOptions = LoanSupportedInterestRefundTypes .getValuesAsStringEnumOptionDataList(); + final List chargeOffReasonOptions = codeValueReadPlatformService + .retrieveCodeValuesByCode(LoanApiConstants.CHARGE_OFF_REASONS); return new LoanProductData(productData, chargeOptions, penaltyOptions, paymentTypeOptions, currencyOptions, amortizationTypeOptions, interestTypeOptions, interestCalculationPeriodTypeOptions, repaymentFrequencyTypeOptions, interestRateFrequencyTypeOptions, @@ -436,7 +441,7 @@ public class LoanProductsApiResource { advancedPaymentAllocationTransactionTypes, advancedPaymentAllocationFutureInstallmentAllocationRules, advancedPaymentAllocationTypes, LoanScheduleType.getValuesAsEnumOptionDataList(), LoanScheduleProcessingType.getValuesAsEnumOptionDataList(), creditAllocationTransactionTypes, - creditAllocationAllocationTypes, supportedInterestRefundTypesOptions); + creditAllocationAllocationTypes, supportedInterestRefundTypesOptions, chargeOffReasonOptions); } }