diff --git a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java index 120dbf132..da4cabcff 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/organisation/teller/service/TellerManagementReadPlatformServiceImpl.java @@ -564,11 +564,7 @@ public class TellerManagementReadPlatformServiceImpl implements TellerManagement final LocalDate startDate = JdbcSupport.getLocalDate(rs, "start_date"); final LocalDate endDate = JdbcSupport.getLocalDate(rs, "end_date"); - final Integer fullDayFromDB = rs.getInt("full_day"); - Boolean fullDay = false; - if (fullDayFromDB == 1) { - fullDay = true; - } + final Boolean fullDay = rs.getBoolean("full_day"); final String startTime = rs.getString("start_time"); final String endTime = rs.getString("end_time"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java index 3b14b0660..47eb7d89e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoanApiConstants.java @@ -25,6 +25,7 @@ public interface LoanApiConstants { String disbursementDataParameterName = "disbursementData"; String disbursementDateParameterName = "expectedDisbursementDate"; String disbursementPrincipalParameterName = "principal"; + String disbursementReversedParameterName = "reversed"; String disbursementNetDisbursalAmountParameterName = "netDisbursalAmount"; String updatedDisbursementDateParameterName = "updatedExpectedDisbursementDate"; String updatedDisbursementPrincipalParameterName = "updatedPrincipal"; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java index 8c082e213..1cffd9d25 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/api/LoansApiResourceSwagger.java @@ -959,7 +959,7 @@ final class LoansApiResourceSwagger { public GetLoansLoanIdTimeline timeline; public GetLoansLoanIdSummary summary; public GetLoansLoanIdRepaymentSchedule repaymentSchedule; - @Schema(description = "Set of GetLoansLoanIdDisbursementDetails") + @Schema(description = "Set of GetLoansLoanIdTransactions") public Set transactions; @Schema(description = "Set of GetLoansLoanIdDisbursementDetails") public Set disbursementDetails; diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java index 105fdbfe9..f3d72a97d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/Loan.java @@ -59,7 +59,6 @@ import javax.persistence.Table; import javax.persistence.Transient; import javax.persistence.UniqueConstraint; import javax.persistence.Version; -import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.apache.fineract.infrastructure.codes.domain.CodeValue; import org.apache.fineract.infrastructure.core.api.JsonCommand; @@ -143,7 +142,6 @@ import org.apache.fineract.portfolio.repaymentwithpostdatedchecks.domain.PostDat import org.apache.fineract.useradministration.domain.AppUser; import org.springframework.stereotype.Component; -@Slf4j @Entity @Component @Table(name = "m_loan", uniqueConstraints = { @UniqueConstraint(columnNames = { "account_no" }, name = "loan_account_no_UNIQUE"), @@ -916,7 +914,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private Money getTotalAllTrancheDisbursementAmount() { Money amount = Money.zero(getCurrency()); if (isMultiDisburmentLoan()) { - for (final LoanDisbursementDetails loanDisbursementDetail : this.disbursementDetails) { + for (final LoanDisbursementDetails loanDisbursementDetail : getDisbursementDetails()) { amount = amount.plus(loanDisbursementDetail.principal()); } } @@ -1133,7 +1131,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { loanCharge.update(this); if (this.loanProduct.isMultiDisburseLoan() && loanCharge.isTrancheDisbursementCharge()) { loanCharge.getTrancheDisbursementCharge().getloanDisbursementDetails().updateLoan(this); - for (final LoanDisbursementDetails loanDisbursementDetails : this.disbursementDetails) { + for (final LoanDisbursementDetails loanDisbursementDetails : getDisbursementDetails()) { if (loanCharge.getTrancheDisbursementCharge().getloanDisbursementDetails().getId() == null) { if (loanCharge.getTrancheDisbursementCharge().getloanDisbursementDetails().equals(loanDisbursementDetails)) { loanTrancheDisbursementCharge = new LoanTrancheDisbursementCharge(loanCharge, loanDisbursementDetails); @@ -1600,7 +1598,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final JsonArray disbursementDataArray = command.arrayOfParameterNamed(LoanApiConstants.disbursementDataParameterName); if (loanProduct.isDisallowExpectedDisbursements()) { - if (!disbursementDataArray.isEmpty()) { + if (disbursementDataArray != null && !disbursementDataArray.isEmpty()) { final String errorMessage = "For this loan product, disbursement details are not allowed"; throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage); } @@ -1609,11 +1607,12 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { final String errorMessage = "For this loan product, disbursement details must be provided"; throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage); } - } - if (disbursementDataArray.size() > loanProduct.maxTrancheCount()) { - final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount(); - throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage, - loanProduct.maxTrancheCount(), disbursementDetails.size()); + + if (disbursementDataArray.size() > loanProduct.maxTrancheCount()) { + final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount(); + throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage, + loanProduct.maxTrancheCount(), disbursementDetails.size()); + } } } else { this.disbursementDetails.clear(); @@ -1905,7 +1904,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { if (loanDisbursementDetail.actualDisbursementDate() == null) { LocalDate actualDisbursementDate = null; LoanDisbursementDetails disbursementDetails = new LoanDisbursementDetails(expectedDisbursementDate, actualDisbursementDate, - principal, this.netDisbursalAmount); + principal, this.netDisbursalAmount, false); disbursementDetails.updateLoan(this); if (!loanDisbursementDetail.equals(disbursementDetails)) { loanDisbursementDetail.copy(disbursementDetails); @@ -1916,7 +1915,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } else { LocalDate actualDisbursementDate = null; LoanDisbursementDetails disbursementDetails = new LoanDisbursementDetails(expectedDisbursementDate, actualDisbursementDate, - principal, this.netDisbursalAmount); + principal, this.netDisbursalAmount, false); disbursementDetails.updateLoan(this); this.disbursementDetails.add(disbursementDetails); for (LoanTrancheCharge trancheCharge : trancheCharges) { @@ -1959,7 +1958,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public LoanDisbursementDetails fetchLoanDisbursementsById(Long id) { LoanDisbursementDetails loanDisbursementDetail = null; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (id.equals(disbursementDetail.getId())) { loanDisbursementDetail = disbursementDetail; break; @@ -1970,7 +1969,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private List fetchDisbursementIds() { List list = new ArrayList<>(); - for (LoanDisbursementDetails disbursementDetails : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetails : getDisbursementDetails()) { list.add(disbursementDetails.getId()); } return list; @@ -2254,22 +2253,23 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { recalculateAllCharges(); if (loanProduct.isMultiDisburseLoan()) { + List currentDisbursementDetails = getDisbursementDetails(); if (loanProduct.isDisallowExpectedDisbursements()) { - if (!disbursementDetails.isEmpty()) { + if (!currentDisbursementDetails.isEmpty()) { final String errorMessage = "For this loan product, disbursement details are not allowed"; throw new MultiDisbursementDataNotAllowedException(LoanApiConstants.disbursementDataParameterName, errorMessage); } } else { - if (disbursementDetails.isEmpty()) { + if (currentDisbursementDetails.isEmpty()) { final String errorMessage = "For this loan product, disbursement details must be provided"; throw new MultiDisbursementDataRequiredException(LoanApiConstants.disbursementDataParameterName, errorMessage); } } - if (this.disbursementDetails.size() > loanProduct.maxTrancheCount()) { + if (currentDisbursementDetails.size() > loanProduct.maxTrancheCount()) { final String errorMessage = "Number of tranche shouldn't be greter than " + loanProduct.maxTrancheCount(); throw new ExceedingTrancheCountException(LoanApiConstants.disbursementDataParameterName, errorMessage, - loanProduct.maxTrancheCount(), disbursementDetails.size()); + loanProduct.maxTrancheCount(), currentDisbursementDetails.size()); } } this.approvedOnDate = approvedOn; @@ -2463,7 +2463,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private List getDisbursedLoanDisbursementDetails() { List ret = new ArrayList<>(); if (this.disbursementDetails != null && this.disbursementDetails.size() > 0) { - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() != null) { ret.add(disbursementDetail); } @@ -2634,7 +2634,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private Collection fetchUndisbursedDetail() { Collection disbursementDetails = new ArrayList<>(); LocalDate date = null; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() == null) { if (date == null || disbursementDetail.expectedDisbursementDate().compareTo(date) == 0 ? Boolean.TRUE : Boolean.FALSE) { disbursementDetails.add(disbursementDetail); @@ -2653,7 +2653,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { LoanDisbursementDetails details = null; LocalDate date = this.actualDisbursementDate; if (date != null) { - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() != null) { if (disbursementDetail.actualDisbursementDate().isAfter(date) || disbursementDetail.actualDisbursementDate().compareTo(date) == 0 ? Boolean.TRUE : Boolean.FALSE) { @@ -2668,7 +2668,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private boolean isDisbursementMissed() { boolean isDisbursementMissed = false; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() == null && DateUtils.getBusinessLocalDate().isAfter(disbursementDetail.expectedDisbursementDateAsLocalDate())) { isDisbursementMissed = true; @@ -2680,7 +2680,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { public BigDecimal getDisbursedAmount() { BigDecimal principal = BigDecimal.ZERO; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() != null) { principal = principal.add(disbursementDetail.principal()); } @@ -2689,7 +2689,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { } private void removeDisbursementDetail() { - Set details = new HashSet<>(this.disbursementDetails); + Set details = new HashSet<>(getDisbursementDetails()); for (LoanDisbursementDetails disbursementDetail : details) { if (disbursementDetail.actualDisbursementDate() == null) { this.disbursementDetails.remove(disbursementDetail); @@ -2699,10 +2699,15 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private boolean isDisbursementAllowed() { boolean isAllowed = false; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { - if (disbursementDetail.actualDisbursementDate() == null) { - isAllowed = true; - break; + List disbursementDetails = getDisbursementDetails(); + if (disbursementDetails == null || disbursementDetails.size() == 0) { + isAllowed = true; + } else { + for (LoanDisbursementDetails disbursementDetail : disbursementDetails) { + if (disbursementDetail.actualDisbursementDate() == null) { + isAllowed = true; + break; + } } } return isAllowed; @@ -2710,7 +2715,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { private boolean atleastOnceDisbursed() { boolean isDisbursed = false; - for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetail : getDisbursementDetails()) { if (disbursementDetail.actualDisbursementDate() != null) { isDisbursed = true; break; @@ -2926,7 +2931,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { : Boolean.TRUE; this.loanRepaymentScheduleDetail.setPrincipal(this.approvedPrincipal); if (this.loanProduct.isMultiDisburseLoan()) { - for (final LoanDisbursementDetails details : this.disbursementDetails) { + for (final LoanDisbursementDetails details : getDisbursementDetails()) { details.updateActualDisbursementDate(null); } } @@ -5094,10 +5099,20 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { return list; } - public List getDisbursementDetails() { + public List getAllDisbursementDetails() { return this.disbursementDetails; } + public List getDisbursementDetails() { + List currentDisbursementDetails = new ArrayList(); + for (LoanDisbursementDetails disbursementDetail : this.disbursementDetails) { + if (!disbursementDetail.isReversed()) { + currentDisbursementDetails.add(disbursementDetail); + } + } + return currentDisbursementDetails; + } + public ChangedTransactionDetail updateDisbursementDateAndAmountForTranche(final LoanDisbursementDetails disbursementDetails, final JsonCommand command, final Map actualChanges, final ScheduleGeneratorDTO scheduleGeneratorDTO) { final Locale locale = command.extractLocale(); @@ -5552,7 +5567,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { NthDayType nthDayType = null; DayOfWeekType dayOfWeekType = null; final List disbursementData = new ArrayList<>(); - for (LoanDisbursementDetails disbursementDetails : this.disbursementDetails) { + for (LoanDisbursementDetails disbursementDetails : getDisbursementDetails()) { disbursementData.add(disbursementDetails.toData()); } @@ -6215,7 +6230,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { charge.resetToOriginal(loanCurrency()); } } - for (final LoanDisbursementDetails details : this.disbursementDetails) { + for (final LoanDisbursementDetails details : getDisbursementDetails()) { if (actualDisbursementDate.equals(details.actualDisbursementDate())) { this.loanRepaymentScheduleDetail.setPrincipal(getDisbursedAmount().subtract(details.principal())); details.updateActualDisbursementDate(null); @@ -6278,7 +6293,7 @@ public class Loan extends AbstractAuditableWithUTCDateTimeCustom { * get the next repayment LocalDate for rescheduling at the time of disbursement */ public LocalDate getNextPossibleRepaymentDateForRescheduling() { - List loanDisbursementDetails = this.disbursementDetails; + List loanDisbursementDetails = getDisbursementDetails(); LocalDate nextRepaymentDate = DateUtils.getBusinessLocalDate(); for (LoanDisbursementDetails loanDisbursementDetail : loanDisbursementDetails) { if (loanDisbursementDetail.actualDisbursementDate() == null) { diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetails.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetails.java index 8dca91eed..125552d7f 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetails.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetails.java @@ -49,16 +49,20 @@ public class LoanDisbursementDetails extends AbstractPersistableCustom { @Column(name = "net_disbursal_amount", scale = 6, precision = 19) private BigDecimal netDisbursalAmount; + @Column(name = "is_reversed", nullable = false) + private boolean reversed; + protected LoanDisbursementDetails() { } public LoanDisbursementDetails(final LocalDate expectedDisbursementDate, final LocalDate actualDisbursementDate, - final BigDecimal principal, final BigDecimal netDisbursalAmount) { + final BigDecimal principal, final BigDecimal netDisbursalAmount, final boolean reversed) { this.expectedDisbursementDate = expectedDisbursementDate; this.actualDisbursementDate = actualDisbursementDate; this.principal = principal; this.netDisbursalAmount = netDisbursalAmount; + this.reversed = reversed; } public void updateLoan(final Loan loan) { @@ -88,6 +92,7 @@ public class LoanDisbursementDetails extends AbstractPersistableCustom { this.principal = disbursementDetails.principal; this.expectedDisbursementDate = disbursementDetails.expectedDisbursementDate; this.actualDisbursementDate = disbursementDetails.actualDisbursementDate; + this.reversed = disbursementDetails.reversed; } public LocalDate expectedDisbursementDate() { @@ -142,4 +147,11 @@ public class LoanDisbursementDetails extends AbstractPersistableCustom { this.principal = principal; } + public void reverse() { + this.reversed = true; + } + + public boolean isReversed() { + return reversed; + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetailsRepository.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetailsRepository.java new file mode 100644 index 000000000..77da6021f --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/domain/LoanDisbursementDetailsRepository.java @@ -0,0 +1,27 @@ +/** + * 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.portfolio.loanaccount.domain; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; + +public interface LoanDisbursementDetailsRepository + extends JpaRepository, JpaSpecificationExecutor { + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java index e7ba8855b..9c0d3266e 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanReadPlatformServiceImpl.java @@ -1628,7 +1628,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { public Collection retrieveLoanDisbursementDetails(final Long loanId) { final LoanDisbursementDetailMapper rm = new LoanDisbursementDetailMapper(sqlGenerator); final String sql = "select " + rm.schema() - + " where dd.loan_id=? group by dd.id, lc.amount_waived_derived order by dd.expected_disburse_date"; + + " where dd.loan_id=? and dd.is_reversed=false group by dd.id, lc.amount_waived_derived order by dd.expected_disburse_date"; return this.jdbcTemplate.query(sql, rm, loanId); // NOSONAR } @@ -1960,7 +1960,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { sqlBuilder.append(" left join m_floating_rates bfr on bfr.is_base_lending_rate = true"); sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= ?"); sqlBuilder.append(" WHERE ml.loan_status_id = ? "); - sqlBuilder.append(" and ml.is_npa = false "); + sqlBuilder.append(" and ml.is_npa = false and dd.is_reversed = false "); sqlBuilder.append(" and (("); sqlBuilder.append("ml.interest_recalculation_enabled = true "); sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ?)"); @@ -2008,7 +2008,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService { sqlBuilder.append(" left join m_floating_rates bfr on bfr.is_base_lending_rate = true"); sqlBuilder.append(" left join m_floating_rates_periods bfrp on bfr.id = bfrp.floating_rates_id and bfrp.created_date >= ?"); sqlBuilder.append(" WHERE ml.loan_status_id = ? "); - sqlBuilder.append(" and ml.is_npa = false "); + sqlBuilder.append(" and ml.is_npa = false and dd.is_reversed = false "); sqlBuilder.append(" and (("); sqlBuilder.append("ml.interest_recalculation_enabled = true "); sqlBuilder.append(" and (ml.interest_recalcualated_on is null or ml.interest_recalcualated_on <> ? )"); diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java index 55a24f4b6..dbac6b5a5 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanUtilService.java @@ -337,9 +337,13 @@ public class LoanUtilService { netDisbursalAmount = jsonObject.getAsJsonPrimitive(LoanApiConstants.disbursementNetDisbursalAmountParameterName) .getAsBigDecimal(); } - - disbursementDatas.add( - new LoanDisbursementDetails(expectedDisbursementDate, actualDisbursementDate, principal, netDisbursalAmount)); + boolean isReversed = false; + if (jsonObject.has(LoanApiConstants.disbursementReversedParameterName)) { + isReversed = this.fromApiJsonHelper.extractBooleanNamed(LoanApiConstants.disbursementReversedParameterName, + jsonObject); + } + disbursementDatas.add(new LoanDisbursementDetails(expectedDisbursementDate, actualDisbursementDate, principal, + netDisbursalAmount, isReversed)); i++; } while (i < disbursementDataArray.size()); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java index 19c9462b5..3a59b7a19 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanaccount/service/LoanWritePlatformServiceJpaRepositoryImpl.java @@ -164,6 +164,7 @@ import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy; import org.apache.fineract.portfolio.loanaccount.domain.LoanChargeRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanCollateralManagement; import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetails; +import org.apache.fineract.portfolio.loanaccount.domain.LoanDisbursementDetailsRepository; import org.apache.fineract.portfolio.loanaccount.domain.LoanEvent; import org.apache.fineract.portfolio.loanaccount.domain.LoanInstallmentCharge; import org.apache.fineract.portfolio.loanaccount.domain.LoanInterestRecalcualtionAdditionalDetails; @@ -269,7 +270,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf private final LoanRepository loanRepository; private final RepaymentWithPostDatedChecksAssembler repaymentWithPostDatedChecksAssembler; private final PostDatedChecksRepository postDatedChecksRepository; - + private final LoanDisbursementDetailsRepository loanDisbursementDetailsRepository; private final LoanRepaymentScheduleInstallmentRepository loanRepaymentScheduleInstallmentRepository; private LoanLifecycleStateMachine defaultLoanLifecycleStateMachine() { @@ -325,9 +326,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf // products final LocalDate artificialExpectedDate = loan.getExpectedDisbursedOnLocalDate(); LoanDisbursementDetails disbursementDetail = new LoanDisbursementDetails(artificialExpectedDate, null, - loan.getDisbursedAmount(), null); + loan.getDisbursedAmount(), null, false); disbursementDetail.updateLoan(loan); - loan.getDisbursementDetails().add(disbursementDetail); + loan.getAllDisbursementDetails().add(disbursementDetail); } } loan.validateAccountStatus(LoanEvent.LOAN_DISBURSED); @@ -869,6 +870,19 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf final Map accountingBridgeData = loan.deriveAccountingBridgeData(currency.getCode(), existingTransactionIds, existingReversedTransactionIds, isAccountTransfer); journalEntryWritePlatformService.createJournalEntriesForLoan(accountingBridgeData); + + // Remove All the Disbursement Details If the Loan Product is disabled and exists one + if (loan.loanProduct().isDisallowExpectedDisbursements()) { + if (!loan.getDisbursementDetails().isEmpty()) { + List reversedDisbursementDetails = new ArrayList(); + for (LoanDisbursementDetails disbursementDetail : loan.getAllDisbursementDetails()) { + disbursementDetail.reverse(); + reversedDisbursementDetails.add(disbursementDetail); + } + this.loanDisbursementDetailsRepository.saveAllAndFlush(reversedDisbursementDetails); + } + } + businessEventNotifierService.notifyPostBusinessEvent(new LoanUndoDisbursalBusinessEvent(loan)); } diff --git a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java index 6d70ee447..04d604094 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java +++ b/fineract-provider/src/main/java/org/apache/fineract/portfolio/loanproduct/api/LoanProductsApiResourceSwagger.java @@ -1237,6 +1237,8 @@ final class LoanProductsApiResourceSwagger { @Schema(example = "50") public Integer principalThresholdForLastInstalment; public GetDelinquencyBucketsResponse delinquencyBucket; + @Schema(example = "true") + public Boolean disallowExpectedDisbursements; } @Schema(description = "PutLoanProductsProductIdRequest") 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 179aaf743..6d8ff7c18 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 @@ -69,4 +69,5 @@ + diff --git a/fineract-provider/src/main/resources/db/changelog/tenant/parts/0050_add_reverse_flag_disbursement_details.xml b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0050_add_reverse_flag_disbursement_details.xml new file mode 100644 index 000000000..fe24671a9 --- /dev/null +++ b/fineract-provider/src/main/resources/db/changelog/tenant/parts/0050_add_reverse_flag_disbursement_details.xml @@ -0,0 +1,33 @@ + + + + + + + + + + + + diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java index c4646906e..2cf2d83ab 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/ClientLoanNonTrancheMultipleDisbursementsIntegrationTest.java @@ -25,6 +25,7 @@ import io.restassured.specification.RequestSpecification; import io.restassured.specification.ResponseSpecification; import java.util.ArrayList; import java.util.HashMap; +import org.apache.fineract.client.models.GetLoansLoanIdResponse; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.Utils; import org.apache.fineract.integrationtests.common.loans.LoanApplicationTestBuilder; @@ -75,7 +76,7 @@ public class ClientLoanNonTrancheMultipleDisbursementsIntegrationTest { .withMultiDisburse() // .withInterestCalculationPeriodTypeAsRepaymentPeriod(true) // .withMaxTrancheCount("30") // - .withDisallowExpectectedDisbursements(true); + .withDisallowExpectedDisbursements(true); if (isInterestRecalculationEnabled) { final String interestRecalculationCompoundingMethod = LoanProductTestBuilder.RECALCULATION_COMPOUNDING_METHOD_NONE; final String rescheduleStrategyMethod = LoanProductTestBuilder.RECALCULATION_STRATEGY_REDUCE_NUMBER_OF_INSTALLMENTS; @@ -160,8 +161,12 @@ public class ClientLoanNonTrancheMultipleDisbursementsIntegrationTest { LOG.info("-------------------------------DISBURSE non-tranch multi-disbursal loan ----------"); final String netDisbursedAmt = null; - loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithNetDisbursalAmount(submitDate, loanID, approved.toString(), - netDisbursedAmt); + loanStatusHashMap = this.loanTransactionHelper.disburseLoanWithTransactionAmount(submitDate, loanID, approved.toString()); + + GetLoansLoanIdResponse getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanID); + Assertions.assertNotNull(getLoansLoanIdResponse); + + this.loanTransactionHelper.printRepaymentSchedule(getLoansLoanIdResponse); LoanStatusChecker.verifyLoanIsActive(loanStatusHashMap); loanSchedule = this.loanTransactionHelper.getLoanRepaymentSchedule(this.requestSpec, this.responseSpec, loanID); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java index 6b6df5410..8c1cc4e74 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/LoanDisbursementDetailsIntegrationTest.java @@ -35,9 +35,12 @@ import java.util.HashMap; import java.util.List; import java.util.Locale; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoansLoanIdResponse; +import org.apache.fineract.client.models.PutLoansLoanIdResponse; import org.apache.fineract.integrationtests.common.ClientHelper; import org.apache.fineract.integrationtests.common.CollateralManagementHelper; import org.apache.fineract.integrationtests.common.Utils; @@ -271,8 +274,6 @@ public class LoanDisbursementDetailsIntegrationTest { @Test public void validateEqualInstallmentsForMultiTrancheLoan() { - List emptyTranches = new ArrayList<>(); - final String operationDate = "01 January 2014"; final String principal = "1000"; final String disbursedPrincipal = "900"; @@ -284,7 +285,7 @@ public class LoanDisbursementDetailsIntegrationTest { .withInterestTypeAsDecliningBalance().withMoratorium("", "").withInterestCalculationPeriodTypeAsRepaymentPeriod(true) .withInterestTypeAsDecliningBalance() // .withMultiDisburse() // - .withDisallowExpectectedDisbursements(true) // + .withDisallowExpectedDisbursements(true) // .build(null); log.info("Product {}", loanProductJSON); final Integer loanProductId = this.loanTransactionHelper.getLoanProductId(loanProductJSON); @@ -294,7 +295,7 @@ public class LoanDisbursementDetailsIntegrationTest { log.info("-------------------LOAN CREATED WITH loanId----------------- {}", loanId); - this.loanTransactionHelper.approveLoanWithApproveAmount(operationDate, expectedDisbursementDate, principal, loanId, emptyTranches); + this.loanTransactionHelper.approveLoanWithApproveAmount(operationDate, expectedDisbursementDate, principal, loanId, null); log.info("-------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY-------"); GetLoansLoanIdResponse getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); @@ -347,6 +348,101 @@ public class LoanDisbursementDetailsIntegrationTest { this.editLoanDisbursementDetails(); } + @Test + public void allowModifyLoanApplicationAfterUndoDisbursalWithTranches() throws ParseException { + final String operationDate = this.approveDate; + List tranches = new ArrayList<>(); + String principal = "1000"; + final List collaterals = new ArrayList<>(); + + final Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec, operationDate); + log.info("---------------------------------CLIENT CREATED WITH ID--------------------------------------------------- {}", clientId); + + final Integer loanProductId = this.loanTransactionHelper + .getLoanProductId(new LoanProductTestBuilder().withInterestTypeAsDecliningBalance().withTranches(true) + .withDisallowExpectedDisbursements(true).withInterestCalculationPeriodTypeAsRepaymentPeriod(true).build(null)); + log.info("----------------------------------LOAN PRODUCT CREATED WITH ID------------------------------------------- {}", + loanProductId); + GetLoanProductsProductIdResponse getLoanProductsProductIdResponse = this.loanTransactionHelper.getLoanProduct(loanProductId); + assertNotNull(getLoanProductsProductIdResponse); + log.info("Loan Product Id {} with DisallowExpectectedDisbursements in {}", loanProductId, + getLoanProductsProductIdResponse.getDisallowExpectedDisbursements()); + assertEquals(true, getLoanProductsProductIdResponse.getDisallowExpectedDisbursements()); + + final Integer loanId = applyForLoanApplicationWithTranches(clientId, loanProductId, proposedAmount, tranches); + log.info("-----------------------------------LOAN CREATED WITH LOANID------------------------------------------------- {}", loanId); + + loanTransactionHelper.approveLoanWithApproveAmount(operationDate, operationDate, approvalAmount, loanId, tranches); + GetLoansLoanIdResponse getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + log.info("-------------------MULTI DISBURSAL LOAN APPROVED SUCCESSFULLY-------"); + assertEquals(0, getLoansLoanIdResponse.getDisbursementDetails().size(), "Disbursement details items"); + + loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, loanId, principal); + + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + log.info("-------------------MULTI DISBURSAL LOAN DISBURSED SUCCESSFULLY-------"); + assertEquals(1, getLoansLoanIdResponse.getDisbursementDetails().size(), "Disbursement details items"); + + PostLoansLoanIdResponse postLoansLoanIdResponse = this.loanTransactionHelper.applyLoanCommand(loanId, "undoDisbursal"); + assertNotNull(postLoansLoanIdResponse); + log.info("-------------------UNDO DISBURSAL LOAN SUCCESSFULLY-------"); + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + assertEquals(0, getLoansLoanIdResponse.getDisbursementDetails().size(), "Disbursement details items"); + + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + assertEquals(0, getLoansLoanIdResponse.getDisbursementDetails().size(), "Disbursement details items"); + + postLoansLoanIdResponse = this.loanTransactionHelper.applyLoanCommand(loanId, "undoApproval"); + assertNotNull(postLoansLoanIdResponse); + log.info("-------------------UNDO APPROVAL LOAN SUCCESSFULLY-------"); + + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + + principal = "10000"; + final String loanApplicationJSON = buildLoanApplicationJSON(clientId, loanProductId, principal, tranches, operationDate, + collaterals); + log.info("Modify Loan Application: {}", loanApplicationJSON); + PutLoansLoanIdResponse putLoansLoanIdResponse = this.loanTransactionHelper.modifyLoanApplication(loanId, loanApplicationJSON); + assertNotNull(putLoansLoanIdResponse); + + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {} and Principal {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size(), + getLoansLoanIdResponse.getPrincipal()); + + // ReDo the Approval and Disbursement + loanTransactionHelper.approveLoanWithApproveAmount(operationDate, operationDate, approvalAmount, loanId, null); + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + + loanTransactionHelper.disburseLoanWithTransactionAmount(operationDate, loanId, principal); + + getLoansLoanIdResponse = this.loanTransactionHelper.getLoan(requestSpec, responseSpec, loanId); + assertNotNull(getLoansLoanIdResponse); + log.info("Loan Id {} with Status {} with Disbursement details {}", getLoansLoanIdResponse.getId(), + getLoansLoanIdResponse.getStatus().getCode(), getLoansLoanIdResponse.getDisbursementDetails().size()); + log.info("-------------------MULTI DISBURSAL LOAN DISBURSED SUCCESSFULLY-------"); + assertEquals(1, getLoansLoanIdResponse.getDisbursementDetails().size(), "Disbursement details items"); + } + private void editLoanDisbursementDetails() throws ParseException { this.editDateAndPrincipalOfExistingTranche(); this.addNewDisbursementDetails(); @@ -412,17 +508,10 @@ public class LoanDisbursementDetailsIntegrationTest { return date; } - private Integer applyForLoanApplicationWithTranches(final Integer clientId, final Integer loanProductId, String principal, - List tranches) { - log.info("----------------APPLYING FOR LOAN APPLICATION"); - List collaterals = new ArrayList<>(); - final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); - Assertions.assertNotNull(collateralId); - final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, - clientId.toString(), collateralId); - Assertions.assertNotNull(clientCollateralId); - addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); - final String loanApplicationJSON = new LoanApplicationTestBuilder() // + private String buildLoanApplicationJSON(final Integer clientId, final Integer loanProductId, String principal, List tranches, + final String operationDate, List collaterals) { + + return new LoanApplicationTestBuilder() // .withPrincipal(principal) // .withLoanTermFrequency("5") // .withLoanTermFrequencyAsMonths() // @@ -435,6 +524,20 @@ public class LoanDisbursementDetailsIntegrationTest { .withInterestTypeAsDecliningBalance() // .withSubmittedOnDate("01 March 2014") // .withCollaterals(collaterals).build(clientId.toString(), loanProductId.toString(), null); + } + + private Integer applyForLoanApplicationWithTranches(final Integer clientId, final Integer loanProductId, String principal, + List tranches) { + log.info("----------------APPLYING FOR LOAN APPLICATION"); + List collaterals = new ArrayList<>(); + final Integer collateralId = CollateralManagementHelper.createCollateralProduct(this.requestSpec, this.responseSpec); + Assertions.assertNotNull(collateralId); + final Integer clientCollateralId = CollateralManagementHelper.createClientCollateral(this.requestSpec, this.responseSpec, + clientId.toString(), collateralId); + Assertions.assertNotNull(clientCollateralId); + addCollaterals(collaterals, clientCollateralId, BigDecimal.valueOf(1)); + final String loanApplicationJSON = buildLoanApplicationJSON(clientId, loanProductId, principal, tranches, "01 March 2014", + collaterals); return this.loanTransactionHelper.getLoanId(loanApplicationJSON); } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java index 936dee5f4..b11fa5f0b 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanProductTestBuilder.java @@ -394,7 +394,7 @@ public class LoanProductTestBuilder { return this; } - public LoanProductTestBuilder withDisallowExpectectedDisbursements(boolean disallowExpectectedDisbursements) { + public LoanProductTestBuilder withDisallowExpectedDisbursements(boolean disallowExpectectedDisbursements) { this.disallowExpectedDisbursements = disallowExpectectedDisbursements; if (this.disallowExpectedDisbursements) { this.allowApprovedDisbursedAmountsOverApplied = true; diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java index 890d2d6f2..96c51a0f5 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/common/loans/LoanTransactionHelper.java @@ -45,7 +45,9 @@ import org.apache.fineract.client.models.GetLoanProductsProductIdResponse; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentPeriod; import org.apache.fineract.client.models.GetLoansLoanIdRepaymentSchedule; import org.apache.fineract.client.models.GetLoansLoanIdResponse; +import org.apache.fineract.client.models.PostLoansLoanIdResponse; import org.apache.fineract.client.models.PostLoansLoanIdTransactionsResponse; +import org.apache.fineract.client.models.PutLoansLoanIdResponse; import org.apache.fineract.client.util.JSON; import org.apache.fineract.integrationtests.common.CommonConstants; import org.apache.fineract.integrationtests.common.Utils; @@ -136,6 +138,12 @@ public class LoanTransactionHelper { "/fineract-provider/api/v1/loans/" + id + "?" + Utils.TENANT_IDENTIFIER, loanApplicationJSON, "loanId"); } + public PutLoansLoanIdResponse modifyLoanApplication(final Integer id, final String loanApplicationJSON) { + final String response = Utils.performServerPut(this.requestSpec, this.responseSpec, + "/fineract-provider/api/v1/loans/" + id + "?" + Utils.TENANT_IDENTIFIER, loanApplicationJSON, null); + return GSON.fromJson(response, PutLoansLoanIdResponse.class); + } + public ArrayList getLoanRepaymentSchedule(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final Integer loanID) { final String URL = "/fineract-provider/api/v1/loans/" + loanID + "?associations=repaymentSchedule&" + Utils.TENANT_IDENTIFIER; @@ -319,6 +327,21 @@ public class LoanTransactionHelper { getDisburseLoanAsJSON(date, null, netDisbursalAmount)); } + public PostLoansLoanIdResponse applyLoanCommand(final Integer loanId, final String command) { + String undoBodyJson = "{}"; + String url = ""; + if (command.equals(UNDO_APPROVAL_LOAN_COMMAND)) { + undoBodyJson = "{'note':'UNDO APPROVAL'}"; + url = createLoanOperationURL(UNDO_APPROVAL_LOAN_COMMAND, loanId); + } else if (command.equals(UNDO_DISBURSE_LOAN_COMMAND)) { + undoBodyJson = "{'note' : 'UNDO DISBURSAL'}"; + url = createLoanOperationURL(UNDO_DISBURSE_LOAN_COMMAND, loanId); + } + final String response = Utils.performServerPost(this.requestSpec, this.responseSpec, url, undoBodyJson, null); + log.info("Response {}", response); + return GSON.fromJson(response, PostLoansLoanIdResponse.class); + } + public HashMap undoDisbursal(final Integer loanID) { final String undoDisburseJson = "{'note' : 'UNDO DISBURSAL'}"; log.info("IN DISBURSE LOAN"); @@ -807,6 +830,8 @@ public class LoanTransactionHelper { } private HashMap performLoanTransaction(final String postURLForLoanTransaction, final String jsonToBeSent) { + log.info("URL: {}", postURLForLoanTransaction); + log.info("Body: {}", jsonToBeSent); final HashMap response = Utils.performServerPost(this.requestSpec, this.responseSpec, postURLForLoanTransaction, jsonToBeSent, "changes"); return (HashMap) response.get("status");