FINERACT-2398: Re-amortization:- Preview Schedule API during re-amortization
This commit is contained in:
committed by
Adam Saghy
parent
c70edf65f8
commit
ad90d98aa0
+25
@@ -66,6 +66,7 @@ import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.request.ReAgePreviewRequest;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.request.ReAmortizationPreviewRequest;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanRepaymentScheduleInstallmentData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.LoanTransactionData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
@@ -76,6 +77,7 @@ import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleD
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanChargePaidByReadService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.reaging.LoanReAgingService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.reamortization.LoanReAmortizationService;
|
||||
import org.apache.fineract.portfolio.paymenttype.data.PaymentTypeData;
|
||||
import org.apache.fineract.portfolio.paymenttype.service.PaymentTypeReadPlatformService;
|
||||
import org.springframework.data.domain.Page;
|
||||
@@ -111,6 +113,7 @@ public class LoanTransactionsApiResource {
|
||||
private final PaymentTypeReadPlatformService paymentTypeReadPlatformService;
|
||||
private final LoanChargePaidByReadService loanChargePaidByReadService;
|
||||
private final LoanReAgingService loanReAgingService;
|
||||
private final LoanReAmortizationService loanReAmortizationService;
|
||||
|
||||
@GET
|
||||
@Path("{loanId}/transactions/template")
|
||||
@@ -806,4 +809,26 @@ public class LoanTransactionsApiResource {
|
||||
return loanReAgingService.previewReAge(null, loanExternalId, reAgePreviewRequest);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("{loanId}/transactions/reamortized-preview")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Preview Re-Amortized Schedule", description = "Generates a preview of the re-amortized loan schedule based on the provided parameters without creating any transactions or modifying the loan.")
|
||||
public LoanScheduleData previewReAmortizationSchedule(
|
||||
@PathParam("loanId") @Parameter(description = "loanId", required = true) final Long loanId,
|
||||
@Valid @BeanParam final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||
return loanReAmortizationService.previewReAmortization(loanId, null, reAmortizationPreviewRequest);
|
||||
}
|
||||
|
||||
@GET
|
||||
@Path("external-id/{loanExternalId}/transactions/reamortized-preview")
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Operation(summary = "Preview Re-amortized Schedule", description = "Generates a preview of the re-amortized loan schedule based on the provided parameters without creating any transactions or modifying the loan.")
|
||||
public LoanScheduleData previewReAmortizationSchedule(
|
||||
@PathParam("loanExternalId") @Parameter(description = "loanExternalId", required = true) final String loanExternalId,
|
||||
@Valid @BeanParam final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
this.context.authenticatedUser().validateHasReadPermission(RESOURCE_NAME_FOR_PERMISSIONS);
|
||||
return loanReAmortizationService.previewReAmortization(null, loanExternalId, reAmortizationPreviewRequest);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
/**
|
||||
* 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.api.request;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.ws.rs.QueryParam;
|
||||
import java.io.Serial;
|
||||
import java.io.Serializable;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType;
|
||||
import org.apache.fineract.validation.constraints.EnumValue;
|
||||
|
||||
@Builder
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class ReAmortizationPreviewRequest implements Serializable {
|
||||
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@QueryParam("reAmortizationInterestHandling")
|
||||
@Parameter(description = "The interest handling type (DEFAULT, WAIVE_INTEREST, EQUAL_AMORTIZATION_INTEREST_SPLIT)", required = true)
|
||||
@NotBlank(message = "{org.apache.fineract.reamortization.interest-handling-type.not-blank}")
|
||||
@EnumValue(enumClass = LoanReAmortizationInterestHandlingType.class, message = "{org.apache.fineract.interest-handling-type.invalid}")
|
||||
private String reAmortizationInterestHandling;
|
||||
|
||||
}
|
||||
+77
-3
@@ -22,10 +22,12 @@ import static java.math.BigDecimal.ZERO;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.time.LocalDate;
|
||||
import java.util.Collection;
|
||||
import java.util.Comparator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||
@@ -40,17 +42,27 @@ import org.apache.fineract.infrastructure.event.business.domain.loan.reamortizat
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reamortization.LoanReAmortizeTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reamortization.LoanUndoReAmortizeTransactionBusinessEvent;
|
||||
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
|
||||
import org.apache.fineract.organisation.monetary.data.CurrencyData;
|
||||
import org.apache.fineract.organisation.monetary.domain.Money;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.LoanReAmortizationApiConstants;
|
||||
import org.apache.fineract.portfolio.loanaccount.api.request.ReAmortizationPreviewRequest;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.DisbursementData;
|
||||
import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLoanData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationInterestHandlingType;
|
||||
import org.apache.fineract.portfolio.loanaccount.domain.reamortization.LoanReAmortizationParameter;
|
||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||
import org.springframework.stereotype.Service;
|
||||
@@ -70,6 +82,9 @@ public class LoanReAmortizationService {
|
||||
private final ReprocessLoanTransactionsService reprocessLoanTransactionsService;
|
||||
private final CodeValueRepository codeValueRepository;
|
||||
private final LoanScheduleService loanScheduleService;
|
||||
private final LoanRepaymentScheduleService loanRepaymentScheduleService;
|
||||
private final LoanReadPlatformService loanReadPlatformService;
|
||||
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
||||
|
||||
public CommandProcessingResult reAmortize(final Long loanId, final JsonCommand command) {
|
||||
final Loan loan = loanAssembler.assembleFrom(loanId);
|
||||
@@ -77,7 +92,7 @@ public class LoanReAmortizationService {
|
||||
|
||||
final LoanTransaction reAmortizeTransaction = createReAmortizeTransaction(loan, command);
|
||||
reAmortizeTransaction.setLoanReAmortizationParameter(createReAmortizationParameter(reAmortizeTransaction, command));
|
||||
processReAmortizationTransaction(loan, reAmortizeTransaction);
|
||||
processReAmortizationTransaction(loan, reAmortizeTransaction, true);
|
||||
loanTransactionRepository.saveAndFlush(reAmortizeTransaction);
|
||||
|
||||
final Map<String, Object> changes = new LinkedHashMap<>();
|
||||
@@ -130,6 +145,36 @@ public class LoanReAmortizationService {
|
||||
.with(changes).build();
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
public LoanScheduleData previewReAmortization(final Long loanId, final String loanExternalId,
|
||||
final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
final Loan loan = loanId != null ? loanAssembler.assembleFrom(loanId)
|
||||
: loanAssembler.assembleFrom(ExternalIdFactory.produce(loanExternalId), false);
|
||||
return previewReAmortization(loan, reAmortizationPreviewRequest);
|
||||
}
|
||||
|
||||
private LoanScheduleData previewReAmortization(final Loan loan, final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
reAmortizationValidator.validateReAmortize(loan);
|
||||
|
||||
final LoanTransaction reAmortizeTransaction = createReAmortizeTransactionFromPreviewRequest(loan, reAmortizationPreviewRequest);
|
||||
processReAmortizationTransaction(loan, reAmortizeTransaction, false);
|
||||
loan.updateLoanScheduleDependentDerivedFields();
|
||||
|
||||
final CurrencyData currencyData = new CurrencyData(loan.getCurrencyCode(), null, loan.getCurrency().getDigitsAfterDecimal(),
|
||||
loan.getCurrency().getInMultiplesOf(), null, null);
|
||||
final RepaymentScheduleRelatedLoanData repaymentScheduleRelatedLoanData = new RepaymentScheduleRelatedLoanData(
|
||||
loan.getDisbursementDate(), loan.getDisbursementDate(), currencyData, loan.getPrincipal().getAmount(),
|
||||
loan.getInArrearsTolerance().getAmount(), ZERO);
|
||||
final Collection<DisbursementData> disbursementData = loanReadPlatformService.retrieveLoanDisbursementDetails(loan.getId());
|
||||
final Collection<LoanTransactionRepaymentPeriodData> capitalizedIncomeData = loanCapitalizedIncomeBalanceRepository
|
||||
.findRepaymentPeriodDataByLoanId(loan.getId());
|
||||
final List<LoanRepaymentScheduleInstallment> sortedInstallments = loan.getRepaymentScheduleInstallments().stream()
|
||||
.sorted(Comparator.comparingInt(LoanRepaymentScheduleInstallment::getInstallmentNumber)).collect(Collectors.toList());
|
||||
|
||||
return loanRepaymentScheduleService.extractLoanScheduleData(sortedInstallments, repaymentScheduleRelatedLoanData, disbursementData,
|
||||
capitalizedIncomeData, loan.isInterestRecalculationEnabled(), loan.getLoanProductRelatedDetail().getLoanScheduleType());
|
||||
}
|
||||
|
||||
private void reverseReAmortizeTransaction(LoanTransaction reAmortizeTransaction, JsonCommand command) {
|
||||
ExternalId reversalExternalId = externalIdFactory.createFromCommand(command,
|
||||
LoanReAmortizationApiConstants.externalIdParameterName);
|
||||
@@ -163,6 +208,23 @@ public class LoanReAmortizationService {
|
||||
txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId);
|
||||
}
|
||||
|
||||
private LoanTransaction createReAmortizeTransactionFromPreviewRequest(final Loan loan,
|
||||
final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
// re-amortization transaction date is always the current business date
|
||||
final LocalDate transactionDate = DateUtils.getBusinessLocalDate();
|
||||
final Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate);
|
||||
final BigDecimal txPrincipalAmount = txPrincipal.getAmount();
|
||||
|
||||
final LoanTransaction reAmortizationTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAMORTIZE,
|
||||
transactionDate, txPrincipalAmount, txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, null);
|
||||
|
||||
final LoanReAmortizationParameter reAmortizationParameter = createReAmortizationParameterFromPreviewRequest(
|
||||
reAmortizationTransaction, reAmortizationPreviewRequest);
|
||||
reAmortizationTransaction.setLoanReAmortizationParameter(reAmortizationParameter);
|
||||
|
||||
return reAmortizationTransaction;
|
||||
}
|
||||
|
||||
private LoanReAmortizationParameter createReAmortizationParameter(LoanTransaction reAmortizationTransaction, JsonCommand command) {
|
||||
LoanReAmortizationInterestHandlingType reAmortizationInterestHandlingType = command.enumValueOfParameterNamed(
|
||||
LoanReAmortizationApiConstants.reAmortizationInterestHandlingParamName, LoanReAmortizationInterestHandlingType.class);
|
||||
@@ -179,10 +241,22 @@ public class LoanReAmortizationService {
|
||||
return new LoanReAmortizationParameter(reAmortizationTransaction, reAmortizationInterestHandlingType, reasonCodeValue);
|
||||
}
|
||||
|
||||
private void processReAmortizationTransaction(final Loan loan, final LoanTransaction reAmortizationTransaction) {
|
||||
private LoanReAmortizationParameter createReAmortizationParameterFromPreviewRequest(final LoanTransaction reAmortizationTransaction,
|
||||
final ReAmortizationPreviewRequest reAmortizationPreviewRequest) {
|
||||
final LoanReAmortizationInterestHandlingType reAmortizationInterestHandlingType = LoanReAmortizationInterestHandlingType
|
||||
.valueOf(reAmortizationPreviewRequest.getReAmortizationInterestHandling());
|
||||
return new LoanReAmortizationParameter(reAmortizationTransaction, reAmortizationInterestHandlingType, null);
|
||||
}
|
||||
|
||||
private void processReAmortizationTransaction(final Loan loan, final LoanTransaction reAmortizationTransaction,
|
||||
final boolean withPostTransactionChecks) {
|
||||
if (loan.isInterestBearingAndInterestRecalculationEnabled()) {
|
||||
loanScheduleService.regenerateRepaymentSchedule(loan);
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAmortizationTransaction));
|
||||
if (withPostTransactionChecks) {
|
||||
reprocessLoanTransactionsService.reprocessTransactions(loan, List.of(reAmortizationTransaction));
|
||||
} else {
|
||||
reprocessLoanTransactionsService.reprocessTransactionsWithoutChecks(loan, List.of(reAmortizationTransaction));
|
||||
}
|
||||
} else {
|
||||
reprocessLoanTransactionsService.processLatestTransaction(reAmortizationTransaction, loan);
|
||||
}
|
||||
|
||||
+4
@@ -54,6 +54,10 @@ public class LoanReAmortizationValidator {
|
||||
validateReAmortizeBusinessRules(loan);
|
||||
}
|
||||
|
||||
public void validateReAmortize(final Loan loan) {
|
||||
validateReAmortizeBusinessRules(loan);
|
||||
}
|
||||
|
||||
private void validateReAmortizeRequest(JsonCommand command) {
|
||||
List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.reAmortization");
|
||||
|
||||
Reference in New Issue
Block a user