diff --git a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java index d2bf2c2b9..579b5e232 100644 --- a/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java +++ b/fineract-core/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainService.java @@ -141,4 +141,6 @@ public interface ConfigurationDomainService { String getAccrualDateConfigForCharge(); + String getNextPaymentDateConfigForLoan(); + } diff --git a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index e89880f11..dbd14e80a 100644 --- a/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-loan/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -190,6 +190,8 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public static final String WRITTEN_OFF_ON_DATE = "writtenOffOnDate"; public static final String FEE = "fee"; public static final String PENALTIES = "penalties"; + public static final String EARLIEST_UNPAID_DATE = "earliest-unpaid-date"; + public static final String NEXT_UNPAID_DUE_DATE = "next-unpaid-due-date"; /** Disable optimistic locking till batch jobs failures can be fixed **/ @Version int version; @@ -3624,7 +3626,40 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return isChronologicallyLatestRepaymentOrWaiver; } - public LocalDate possibleNextRepaymentDate() { + public LocalDate possibleNextRepaymentDate(final String nextPaymentDueDateConfig) { + LocalDate nextPossibleRepaymentDate = null; + if (EARLIEST_UNPAID_DATE.equalsIgnoreCase(nextPaymentDueDateConfig)) { + nextPossibleRepaymentDate = getEarliestUnpaidInstallmentDate(); + } else if (NEXT_UNPAID_DUE_DATE.equalsIgnoreCase(nextPaymentDueDateConfig)) { + nextPossibleRepaymentDate = getNextUnpaidInstallmentDueDate(); + } + return nextPossibleRepaymentDate; + } + + private LocalDate getNextUnpaidInstallmentDueDate() { + LocalDate nextUnpaidInstallmentDate = null; + List installments = getRepaymentScheduleInstallments(); + LocalDate currentBusinessDate = DateUtils.getBusinessLocalDate(); + LocalDate expectedMaturityDate = determineExpectedMaturityDate(); + + for (final LoanRepaymentScheduleInstallment installment : installments) { + boolean isCurrentDateBeforeInstallmentAndLoanPeriod = DateUtils.isBefore(currentBusinessDate, installment.getDueDate()) + && DateUtils.isBefore(currentBusinessDate, expectedMaturityDate); + if (installment.isDownPayment()) { + isCurrentDateBeforeInstallmentAndLoanPeriod = DateUtils.isEqual(currentBusinessDate, installment.getDueDate()) + && DateUtils.isBefore(currentBusinessDate, expectedMaturityDate); + } + if (isCurrentDateBeforeInstallmentAndLoanPeriod) { + if (installment.isNotFullyPaidOff()) { + nextUnpaidInstallmentDate = installment.getDueDate(); + break; + } + } + } + return nextUnpaidInstallmentDate; + } + + private LocalDate getEarliestUnpaidInstallmentDate() { LocalDate earliestUnpaidInstallmentDate = DateUtils.getBusinessLocalDate(); List installments = getRepaymentScheduleInstallments(); for (final LoanRepaymentScheduleInstallment installment : installments) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java index 3cb8a4b6b..58b0bf3dc 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java +++ b/fineract-provider/src/main/java/org/apache/fineract/infrastructure/configuration/domain/ConfigurationDomainServiceJpa.java @@ -53,6 +53,8 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService private static final String REPORT_EXPORT_S3_FOLDER_NAME = "report-export-s3-folder-name"; public static final String CHARGE_ACCRUAL_DATE_CRITERIA = "charge-accrual-date"; + public static final String NEXT_PAYMENT_DUE_DATE = "next-payment-due-date"; + private final PermissionRepository permissionRepository; private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository; private final PlatformCacheRepository cacheTypeRepository; @@ -516,4 +518,15 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService return value; } + @Override + public String getNextPaymentDateConfigForLoan() { + String defaultValue = "earliest-unpaid-date"; + final GlobalConfigurationPropertyData property = getGlobalConfigurationPropertyData(NEXT_PAYMENT_DUE_DATE); + String value = property.getStringValue(); + if (StringUtils.isBlank(value)) { + return defaultValue; + } + return value; + } + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java index b80b51e89..ac8cca761 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/service/DelinquencyReadPlatformServiceImpl.java @@ -26,6 +26,7 @@ import java.util.Optional; import java.util.stream.Collector; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.core.service.MathUtil; import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil; import org.apache.fineract.portfolio.delinquency.data.DelinquencyBucketData; @@ -70,6 +71,7 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo private final LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag; private final LoanDelinquencyActionRepository loanDelinquencyActionRepository; private final DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper; + private final ConfigurationDomainService configurationDomainService; @Override public Collection retrieveAllDelinquencyRanges() { @@ -128,9 +130,11 @@ public class DelinquencyReadPlatformServiceImpl implements DelinquencyReadPlatfo List effectiveDelinquencyList = delinquencyEffectivePauseHelper .calculateEffectiveDelinquencyList(savedDelinquencyList); + final String nextPaymentDueDateConfig = configurationDomainService.getNextPaymentDateConfigForLoan(); + collectionData = loanDelinquencyDomainService.getOverdueCollectionData(loan, effectiveDelinquencyList); collectionData.setAvailableDisbursementAmount(loan.getApprovedPrincipal().subtract(loan.getDisbursedAmount())); - collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate()); + collectionData.setNextPaymentDueDate(loan.possibleNextRepaymentDate(nextPaymentDueDateConfig)); final LoanTransaction lastPayment = loan.getLastPaymentTransaction(); if (lastPayment != null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java index 734a249af..897e62b9a 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/delinquency/starter/DelinquencyConfiguration.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.portfolio.delinquency.starter; +import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService; import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketMappingsRepository; import org.apache.fineract.portfolio.delinquency.domain.DelinquencyBucketRepository; @@ -57,10 +58,11 @@ public class DelinquencyConfiguration { LoanDelinquencyDomainService loanDelinquencyDomainService, LoanInstallmentDelinquencyTagRepository repositoryLoanInstallmentDelinquencyTag, LoanDelinquencyActionRepository loanDelinquencyActionRepository, - DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper) { + DelinquencyEffectivePauseHelper delinquencyEffectivePauseHelper, ConfigurationDomainService configurationDomainService) { return new DelinquencyReadPlatformServiceImpl(repositoryRange, repositoryBucket, repositoryLoanDelinquencyTagHistory, mapperRange, mapperBucket, mapperLoanDelinquencyTagHistory, loanRepository, loanDelinquencyDomainService, - repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository, delinquencyEffectivePauseHelper); + repositoryLoanInstallmentDelinquencyTag, loanDelinquencyActionRepository, delinquencyEffectivePauseHelper, + configurationDomainService); } @Bean diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml index 1c67c7718..f8b434ecc 100644 --- a/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml +++ b/fineract-provider/src/main/resources/db/changelog/tenant/changelog-tenant.xml @@ -151,4 +151,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0132_add_configuration_loan_next_repayment_date_calculation.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0132_add_configuration_loan_next_repayment_date_calculation.xml new file mode 100644 index 000000000..000a1ebcb --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0132_add_configuration_loan_next_repayment_date_calculation.xml @@ -0,0 +1,41 @@ + + + + + + SELECT SETVAL('c_configuration_id_seq', COALESCE(MAX(id), 0)+1, false ) FROM c_configuration; + + + + + + + + + + + + + + diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDelinquencyDetailsNextPaymentDateConfigurationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDelinquencyDetailsNextPaymentDateConfigurationTest.java new file mode 100644 index 000000000..7dc67f4a7 --- /dev/null +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDelinquencyDetailsNextPaymentDateConfigurationTest.java @@ -0,0 +1,299 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.integrationtests; + +import static java.lang.Boolean.TRUE; +import static org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType.BUSINESS_DATE; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; + +import java.math.BigDecimal; +import java.time.LocalDate; +import java.util.List; +import org.apache.commons.lang3.tuple.Pair; +import org.apache.fineract.client.models.BusinessDateRequest; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; +import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoanProductsRequest; +import org.apache.fineract.client.models.PostLoanProductsResponse; +import org.apache.fineract.integrationtests.common.ClientHelper; +import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper; +import org.apache.fineract.integrationtests.common.products.DelinquencyBucketsHelper; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class LoanDelinquencyDetailsNextPaymentDateConfigurationTest extends BaseLoanIntegrationTest { + + public static final BigDecimal DOWN_PAYMENT_PERCENTAGE = new BigDecimal(25); + + @Test + public void testNextPaymentDateForUnpaidInstallmentsWithNPlusOneTest() { + runAt("01 November 2023", () -> { + try { + // update Global configuration for next payment date + GlobalConfigurationHelper.updateLoanNextPaymentDateConfiguration(this.requestSpec, this.responseSpec, + "next-unpaid-due-date"); + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + + // Create Loan Product + Long loanProductId = createLoanProductWith25PctDownPaymentAndDelinquencyBucket(false, true, false, 0); + + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, "01 November 2023", 1000.0, 3, req -> { + req.submittedOnDate("01 November 2023"); + req.setLoanTermFrequency(45); + req.setRepaymentEvery(15); + req.setGraceOnArrearsAgeing(0); + }); + + // Loan amount Disbursement + disburseLoan(loanId, BigDecimal.valueOf(1000.00), "01 November 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, false, "01 November 2023"), // + installment(250.0, false, "16 November 2023"), // + installment(250.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023") // + ); + + // delinquency next payment date for 01 Nov Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "01 November 2023", false); + + // Update business date + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("13 November 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 13 Nov Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "16 November 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("16 November 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 16 Nov Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "01 December 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("01 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 01 Dec Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "16 December 2023", false); + + // add charge with due date after loan maturity date (N + 1) + Long loanChargeId = addCharge(loanId, false, 50, "23 December 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, false, "01 November 2023"), // + installment(250.0, false, "16 November 2023"), // + installment(250.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023"), // + installment(0.0, 0.0, 50.0, 50.0, false, "23 December 2023") // + ); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("17 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 17 Dec Business date N + 1 + verifyLoanDelinquencyNextPaymentDate(loanId, "23 December 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("25 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency null next payment date for date after maturity date + verifyLoanDelinquencyNextPaymentDate(loanId, "", true); + + } finally { + // reset global config + GlobalConfigurationHelper.updateLoanNextPaymentDateConfiguration(this.requestSpec, this.responseSpec, + "earliest-unpaid-date"); + } + + }); + } + + @Test + public void testNextPaymentDateFor2Paid1PartiallyPaidInstallmentsWithNPlusOneTest() { + runAt("01 November 2023", () -> { + try { + // update Global configuration for next payment date + GlobalConfigurationHelper.updateLoanNextPaymentDateConfiguration(this.requestSpec, this.responseSpec, + "next-unpaid-due-date"); + // Create Client + Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); + + // Create Loan Product with auto downpayment enabled + Long loanProductId = createLoanProductWith25PctDownPaymentAndDelinquencyBucket(true, true, false, 0); + + // Apply and Approve Loan + Long loanId = applyAndApproveLoan(clientId, loanProductId, "01 November 2023", 1000.0, 3, req -> { + req.submittedOnDate("01 November 2023"); + req.setLoanTermFrequency(45); + req.setRepaymentEvery(15); + req.setGraceOnArrearsAgeing(0); + }); + + // Loan amount Disbursement + disburseLoan(loanId, BigDecimal.valueOf(1000.00), "01 November 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, true, "01 November 2023"), // + installment(250.0, false, "16 November 2023"), // + installment(250.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023") // + ); + + // delinquency next payment date for 01 Nov Business date with auto paid downpayment installment + verifyLoanDelinquencyNextPaymentDate(loanId, "16 November 2023", false); + + // Update business date + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("13 November 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 13 Nov Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "16 November 2023", false); + + // pay 16 Nov Installment + addRepaymentForLoan(loanId, 250.0, "13 November 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, true, "01 November 2023"), // + installment(250.0, true, "16 November 2023"), // + installment(250.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023")// + ); + + // delinquency next payment date for 13 Nov Business date after paying 16 November Installment + verifyLoanDelinquencyNextPaymentDate(loanId, "01 December 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("16 November 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 16 Nov Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "01 December 2023", false); + + // partially pay 01 December installment + addRepaymentForLoan(loanId, 100.0, "16 November 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, true, "01 November 2023"), // + installment(250.0, true, "16 November 2023"), // + installment(250.0, 0.0, 150.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023")// + ); + + // delinquency next payment date for 16 Nov Business date after partial payment of 01 Dec installment + verifyLoanDelinquencyNextPaymentDate(loanId, "01 December 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("01 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 01 December Business date + verifyLoanDelinquencyNextPaymentDate(loanId, "16 December 2023", false); + + // add charge with due date after loan maturity date (N + 1) + Long loanChargeId = addCharge(loanId, false, 50, "23 December 2023"); + + // verify repayment schedule + verifyRepaymentSchedule(loanId, // + installment(0, null, "01 November 2023"), // + installment(250.0, true, "01 November 2023"), // + installment(250.0, true, "16 November 2023"), // + installment(250.0, 0.0, 150.0, false, "01 December 2023"), // + installment(250.0, false, "16 December 2023"), // + installment(0.0, 0.0, 50.0, 50.0, false, "23 December 2023") // + ); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("17 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency next payment date for 17 Dec Business date N + 1 + verifyLoanDelinquencyNextPaymentDate(loanId, "23 December 2023", false); + + businessDateHelper.updateBusinessDate(new BusinessDateRequest().type(BUSINESS_DATE.getName()).date("25 December 2023") + .dateFormat(DATETIME_PATTERN).locale("en")); + + // delinquency null next payment date for date after maturity date + verifyLoanDelinquencyNextPaymentDate(loanId, "", true); + + } finally { + // reset global config + GlobalConfigurationHelper.updateLoanNextPaymentDateConfiguration(this.requestSpec, this.responseSpec, + "earliest-unpaid-date"); + } + + }); + } + + private void verifyLoanDelinquencyNextPaymentDate(Long loanId, String nextPaymentDate, boolean verifyNull) { + GetLoansLoanIdResponse loan = loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId.intValue()); + Assertions.assertNotNull(loan.getDelinquent()); + if (!verifyNull) { + Assertions.assertNotNull(loan.getDelinquent().getNextPaymentDueDate()); + assertThat(loan.getDelinquent().getNextPaymentDueDate().isEqual(LocalDate.parse(nextPaymentDate, dateTimeFormatter))); + } else { + Assertions.assertNull(loan.getDelinquent().getNextPaymentDueDate()); + } + + } + + private Long createLoanProductWith25PctDownPaymentAndDelinquencyBucket(boolean autoDownPaymentEnabled, boolean multiDisburseEnabled, + boolean installmentLevelDelinquencyEnabled, Integer graceOnArrearsAging) { + // Create DelinquencyBuckets + Integer delinquencyBucketId = DelinquencyBucketsHelper.createDelinquencyBucket(requestSpec, responseSpec, List.of(// + Pair.of(1, 3), // + Pair.of(4, 10), // + Pair.of(11, 60), // + Pair.of(61, null)// + )); + PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProduct(); + product.setDelinquencyBucketId(delinquencyBucketId.longValue()); + product.setMultiDisburseLoan(multiDisburseEnabled); + product.setEnableDownPayment(true); + product.setGraceOnArrearsAgeing(graceOnArrearsAging); + + product.setDisbursedAmountPercentageForDownPayment(DOWN_PAYMENT_PERCENTAGE); + product.setEnableAutoRepaymentForDownPayment(autoDownPaymentEnabled); + product.setEnableInstallmentLevelDelinquency(installmentLevelDelinquencyEnabled); + + PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product); + GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = loanProductHelper + .retrieveLoanProductById(loanProductResponse.getResourceId()); + + Long loanProductId = loanProductResponse.getResourceId(); + + assertEquals(TRUE, getLoanProductsProductIdResponse.getEnableDownPayment()); + assertNotNull(getLoanProductsProductIdResponse.getDisbursedAmountPercentageForDownPayment()); + assertEquals(0, getLoanProductsProductIdResponse.getDisbursedAmountPercentageForDownPayment().compareTo(DOWN_PAYMENT_PERCENTAGE)); + assertEquals(autoDownPaymentEnabled, getLoanProductsProductIdResponse.getEnableAutoRepaymentForDownPayment()); + assertEquals(multiDisburseEnabled, getLoanProductsProductIdResponse.getMultiDisburseLoan()); + return loanProductId; + + } +} diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java index a44b571fb..e098a75cb 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/GlobalConfigurationHelper.java @@ -119,8 +119,8 @@ public class GlobalConfigurationHelper { ArrayList expectedGlobalConfigurations = getAllDefaultGlobalConfigurations(); ArrayList actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec); - Assertions.assertEquals(53, expectedGlobalConfigurations.size()); - Assertions.assertEquals(53, actualGlobalConfigurations.size()); + Assertions.assertEquals(54, expectedGlobalConfigurations.size()); + Assertions.assertEquals(54, actualGlobalConfigurations.size()); for (int i = 0; i < expectedGlobalConfigurations.size(); i++) { @@ -581,6 +581,15 @@ public class GlobalConfigurationHelper { enableSameMakerChecker.put("trapDoor", false); defaults.add(enableSameMakerChecker); + HashMap nextPaymentDateConfigForLoan = new HashMap<>(); + nextPaymentDateConfigForLoan.put("id", 59); + nextPaymentDateConfigForLoan.put("name", "next-payment-due-date"); + nextPaymentDateConfigForLoan.put("value", 0); + nextPaymentDateConfigForLoan.put("enabled", true); + nextPaymentDateConfigForLoan.put("trapDoor", false); + nextPaymentDateConfigForLoan.put("string_value", "earliest-unpaid-date"); + defaults.add(nextPaymentDateConfigForLoan); + return defaults; } @@ -705,4 +714,17 @@ public class GlobalConfigurationHelper { } + public static Integer updateLoanNextPaymentDateConfiguration(final RequestSpecification requestSpec, + final ResponseSpecification responseSpec, final String stringValue) { + long configId = 59; + final HashMap map = new HashMap<>(); + map.put("stringValue", stringValue); + log.info("map : {}", map); + final String configValue = GSON.toJson(map); + final String GLOBAL_CONFIG_UPDATE_URL = "/fineract-provider/api/v1/configurations/" + configId + "?" + Utils.TENANT_IDENTIFIER; + log.info("---------------------------------UPDATE VALUE FOR GLOBAL CONFIG---------------------------------------------"); + return Utils.performServerPut(requestSpec, responseSpec, GLOBAL_CONFIG_UPDATE_URL, configValue, "resourceId"); + + } + }