FINERACT-2354: Validation of Re-age amount during submission
This commit is contained in:
committed by
Adam Saghy
parent
4c22e2a9fc
commit
a58bdf49b6
+1
-1
@@ -178,7 +178,7 @@ public final class JsonCommand {
|
|||||||
this.parsedCommand = parsedCommand;
|
this.parsedCommand = parsedCommand;
|
||||||
this.resourceId = resourceId;
|
this.resourceId = resourceId;
|
||||||
this.commandId = null;
|
this.commandId = null;
|
||||||
this.jsonCommand = null;
|
this.jsonCommand = parsedCommand.toString();
|
||||||
this.fromApiJsonHelper = fromApiJsonHelper;
|
this.fromApiJsonHelper = fromApiJsonHelper;
|
||||||
this.entityName = null;
|
this.entityName = null;
|
||||||
this.subresourceId = null;
|
this.subresourceId = null;
|
||||||
|
|||||||
+3
@@ -31,4 +31,7 @@ public interface LoanReAgingApiConstants {
|
|||||||
|
|
||||||
String reAgeInterestHandlingParamName = "reAgeInterestHandling";
|
String reAgeInterestHandlingParamName = "reAgeInterestHandling";
|
||||||
String reasonCodeValueIdParamName = "reasonCodeValueId";
|
String reasonCodeValueIdParamName = "reasonCodeValueId";
|
||||||
|
|
||||||
|
String transactionAmountParamName = "transactionAmount";
|
||||||
|
String noteParamName = "note";
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-10
@@ -36,9 +36,11 @@ import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
|||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||||
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
import org.apache.fineract.infrastructure.core.domain.ExternalId;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
import org.apache.fineract.infrastructure.core.service.ExternalIdFactory;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.infrastructure.event.business.domain.loan.reaging.LoanReAgeBusinessEvent;
|
import org.apache.fineract.infrastructure.event.business.domain.loan.reaging.LoanReAgeBusinessEvent;
|
||||||
import org.apache.fineract.infrastructure.event.business.domain.loan.reaging.LoanUndoReAgeBusinessEvent;
|
import org.apache.fineract.infrastructure.event.business.domain.loan.reaging.LoanUndoReAgeBusinessEvent;
|
||||||
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reaging.LoanReAgeTransactionBusinessEvent;
|
import org.apache.fineract.infrastructure.event.business.domain.loan.transaction.reaging.LoanReAgeTransactionBusinessEvent;
|
||||||
@@ -55,7 +57,6 @@ import org.apache.fineract.portfolio.loanaccount.data.RepaymentScheduleRelatedLo
|
|||||||
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
import org.apache.fineract.portfolio.loanaccount.data.ScheduleGeneratorDTO;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleTransactionProcessorFactory;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepaymentPeriodData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
|
||||||
@@ -66,12 +67,10 @@ import org.apache.fineract.portfolio.loanaccount.exception.LoanTransactionNotFou
|
|||||||
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
import org.apache.fineract.portfolio.loanaccount.loanschedule.data.LoanScheduleData;
|
||||||
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
import org.apache.fineract.portfolio.loanaccount.repository.LoanCapitalizedIncomeBalanceRepository;
|
||||||
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
import org.apache.fineract.portfolio.loanaccount.serialization.LoanChargeValidator;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.InterestScheduleModelRepositoryWrapper;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanAssembler;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanReadPlatformService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanRepaymentScheduleService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanScheduleService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanTransactionService;
|
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
import org.apache.fineract.portfolio.loanaccount.service.LoanUtilService;
|
||||||
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
import org.apache.fineract.portfolio.loanaccount.service.ReprocessLoanTransactionsService;
|
||||||
import org.apache.fineract.portfolio.note.domain.Note;
|
import org.apache.fineract.portfolio.note.domain.Note;
|
||||||
@@ -89,7 +88,6 @@ public class LoanReAgingService {
|
|||||||
private final ExternalIdFactory externalIdFactory;
|
private final ExternalIdFactory externalIdFactory;
|
||||||
private final BusinessEventNotifierService businessEventNotifierService;
|
private final BusinessEventNotifierService businessEventNotifierService;
|
||||||
private final LoanTransactionRepository loanTransactionRepository;
|
private final LoanTransactionRepository loanTransactionRepository;
|
||||||
private final LoanRepaymentScheduleTransactionProcessorFactory loanRepaymentScheduleTransactionProcessorFactory;
|
|
||||||
private final NoteRepository noteRepository;
|
private final NoteRepository noteRepository;
|
||||||
private final LoanChargeValidator loanChargeValidator;
|
private final LoanChargeValidator loanChargeValidator;
|
||||||
private final LoanUtilService loanUtilService;
|
private final LoanUtilService loanUtilService;
|
||||||
@@ -99,8 +97,6 @@ public class LoanReAgingService {
|
|||||||
private final LoanRepaymentScheduleService loanRepaymentScheduleService;
|
private final LoanRepaymentScheduleService loanRepaymentScheduleService;
|
||||||
private final LoanReadPlatformService loanReadPlatformService;
|
private final LoanReadPlatformService loanReadPlatformService;
|
||||||
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
private final LoanCapitalizedIncomeBalanceRepository loanCapitalizedIncomeBalanceRepository;
|
||||||
private final InterestScheduleModelRepositoryWrapper modelRepository;
|
|
||||||
private final LoanTransactionService loanTransactionService;
|
|
||||||
|
|
||||||
public CommandProcessingResult reAge(final Long loanId, final JsonCommand command) {
|
public CommandProcessingResult reAge(final Long loanId, final JsonCommand command) {
|
||||||
final Loan loan = loanAssembler.assembleFrom(loanId);
|
final Loan loan = loanAssembler.assembleFrom(loanId);
|
||||||
@@ -240,7 +236,15 @@ public class LoanReAgingService {
|
|||||||
}
|
}
|
||||||
// in case of a reaging transaction, only the outstanding principal amount until the business date is considered
|
// in case of a reaging transaction, only the outstanding principal amount until the business date is considered
|
||||||
Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate);
|
Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate);
|
||||||
BigDecimal txPrincipalAmount = txPrincipal.getAmount();
|
final BigDecimal txPrincipalAmount = txPrincipal.getAmount();
|
||||||
|
if (command.hasParameter(LoanReAgingApiConstants.transactionAmountParamName)) {
|
||||||
|
final BigDecimal transactionAmount = command
|
||||||
|
.bigDecimalValueOfParameterNamed(LoanReAgingApiConstants.transactionAmountParamName);
|
||||||
|
if (!MathUtil.isEqualTo(txPrincipalAmount, transactionAmount)) {
|
||||||
|
throw new GeneralPlatformDomainRuleException("error.msg.loan.reage.amount.not.match.with.calculated.reage.amount",
|
||||||
|
"re-age amount is not matching with the calculated re-age amount", txPrincipalAmount);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final LoanTransaction reAgeTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE, transactionDate,
|
final LoanTransaction reAgeTransaction = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE, transactionDate,
|
||||||
txPrincipalAmount, txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId);
|
txPrincipalAmount, txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId);
|
||||||
@@ -275,10 +279,10 @@ public class LoanReAgingService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void persistNote(Loan loan, JsonCommand command, Map<String, Object> changes) {
|
private void persistNote(Loan loan, JsonCommand command, Map<String, Object> changes) {
|
||||||
if (command.hasParameter("note")) {
|
if (command.hasParameter(LoanReAgingApiConstants.noteParamName)) {
|
||||||
final String note = command.stringValueOfParameterNamed("note");
|
final String note = command.stringValueOfParameterNamed(LoanReAgingApiConstants.noteParamName);
|
||||||
final Note newNote = Note.loanNote(loan, note);
|
final Note newNote = Note.loanNote(loan, note);
|
||||||
changes.put("note", note);
|
changes.put(LoanReAgingApiConstants.noteParamName, note);
|
||||||
|
|
||||||
this.noteRepository.saveAndFlush(newNote);
|
this.noteRepository.saveAndFlush(newNote);
|
||||||
}
|
}
|
||||||
|
|||||||
+32
-1
@@ -20,22 +20,30 @@ package org.apache.fineract.portfolio.loanaccount.service.reaging;
|
|||||||
|
|
||||||
import static org.apache.fineract.infrastructure.core.service.DateUtils.getBusinessLocalDate;
|
import static org.apache.fineract.infrastructure.core.service.DateUtils.getBusinessLocalDate;
|
||||||
|
|
||||||
|
import com.google.gson.reflect.TypeToken;
|
||||||
|
import java.lang.reflect.Type;
|
||||||
|
import java.math.BigDecimal;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
import org.apache.fineract.infrastructure.codes.domain.CodeValue;
|
||||||
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
import org.apache.fineract.infrastructure.codes.domain.CodeValueRepository;
|
||||||
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
import org.apache.fineract.infrastructure.core.api.JsonCommand;
|
||||||
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
|
||||||
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
|
||||||
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
import org.apache.fineract.infrastructure.core.exception.GeneralPlatformDomainRuleException;
|
||||||
|
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
|
||||||
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
|
||||||
|
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
|
||||||
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
import org.apache.fineract.infrastructure.core.serialization.JsonParserHelper;
|
||||||
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
import org.apache.fineract.infrastructure.core.service.DateUtils;
|
||||||
|
import org.apache.fineract.infrastructure.core.service.MathUtil;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.LoanReAgingApiConstants;
|
import org.apache.fineract.portfolio.loanaccount.api.LoanReAgingApiConstants;
|
||||||
import org.apache.fineract.portfolio.loanaccount.api.request.ReAgePreviewRequest;
|
import org.apache.fineract.portfolio.loanaccount.api.request.ReAgePreviewRequest;
|
||||||
@@ -54,8 +62,17 @@ public class LoanReAgingValidator {
|
|||||||
|
|
||||||
private final LoanTransactionRepository loanTransactionRepository;
|
private final LoanTransactionRepository loanTransactionRepository;
|
||||||
private final CodeValueRepository codeValueRepository;
|
private final CodeValueRepository codeValueRepository;
|
||||||
|
private final FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
|
private final List<String> reAgeSupportedParameters = List.of(LoanReAgingApiConstants.externalIdParameterName,
|
||||||
|
LoanReAgingApiConstants.startDate, LoanReAgingApiConstants.frequencyType, LoanReAgingApiConstants.frequencyNumber,
|
||||||
|
LoanReAgingApiConstants.numberOfInstallments, LoanReAgingApiConstants.reAgeInterestHandlingParamName,
|
||||||
|
LoanReAgingApiConstants.reasonCodeValueIdParamName, LoanReAgingApiConstants.transactionAmountParamName,
|
||||||
|
LoanReAgingApiConstants.localeParameterName, LoanReAgingApiConstants.dateFormatParameterName,
|
||||||
|
LoanReAgingApiConstants.noteParamName);
|
||||||
|
|
||||||
public void validateReAge(Loan loan, JsonCommand command) {
|
public void validateReAge(Loan loan, JsonCommand command) {
|
||||||
|
validateJSONAndCheckForUnsupportedParams(command.json());
|
||||||
validateReAgeRequest(loan, command);
|
validateReAgeRequest(loan, command);
|
||||||
validateReAgeBusinessRules(loan);
|
validateReAgeBusinessRules(loan);
|
||||||
validateReAgeOutstandingBalance(loan, command);
|
validateReAgeOutstandingBalance(loan, command);
|
||||||
@@ -67,6 +84,15 @@ public class LoanReAgingValidator {
|
|||||||
validateReAgeOutstandingBalance(loan, reAgePreviewRequest);
|
validateReAgeOutstandingBalance(loan, reAgePreviewRequest);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void validateJSONAndCheckForUnsupportedParams(final String json) {
|
||||||
|
if (StringUtils.isBlank(json)) {
|
||||||
|
throw new InvalidJsonException();
|
||||||
|
}
|
||||||
|
|
||||||
|
final Type typeOfMap = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
|
fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json, reAgeSupportedParameters);
|
||||||
|
}
|
||||||
|
|
||||||
private void validateReAgeRequest(Loan loan, JsonCommand command) {
|
private void validateReAgeRequest(Loan loan, JsonCommand command) {
|
||||||
List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||||
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.reAge");
|
DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors).resource("loan.reAge");
|
||||||
@@ -110,6 +136,10 @@ public class LoanReAgingValidator {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final BigDecimal transactionAmount = command.bigDecimalValueOfParameterNamed(LoanReAgingApiConstants.transactionAmountParamName);
|
||||||
|
baseDataValidator.reset().parameter(LoanReAgingApiConstants.transactionAmountParamName).value(transactionAmount).ignoreIfNull()
|
||||||
|
.positiveAmount();
|
||||||
|
|
||||||
throwExceptionIfValidationErrorsExist(dataValidationErrors);
|
throwExceptionIfValidationErrorsExist(dataValidationErrors);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -193,7 +223,8 @@ public class LoanReAgingValidator {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (loan.getSummary().getTotalPrincipalOutstanding().compareTo(java.math.BigDecimal.ZERO) == 0) {
|
final BigDecimal totalPrincipalOutstanding = loan.getSummary().getTotalPrincipalOutstanding();
|
||||||
|
if (MathUtil.isZero(totalPrincipalOutstanding)) {
|
||||||
throw new GeneralPlatformDomainRuleException("error.msg.loan.reage.no.outstanding.balance.to.reage",
|
throw new GeneralPlatformDomainRuleException("error.msg.loan.reage.no.outstanding.balance.to.reage",
|
||||||
"Loan cannot be re-aged as there are no outstanding balances to be re-aged", loan.getId());
|
"Loan cannot be re-aged as there are no outstanding balances to be re-aged", loan.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
+29
@@ -70,6 +70,9 @@ class LoanReAgingValidatorTest {
|
|||||||
@Mock
|
@Mock
|
||||||
private LoanTransactionRepository loanTransactionRepository;
|
private LoanTransactionRepository loanTransactionRepository;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private FromJsonHelper fromApiJsonHelper;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private LoanReAgingValidator underTest;
|
private LoanReAgingValidator underTest;
|
||||||
|
|
||||||
@@ -288,6 +291,32 @@ class LoanReAgingValidatorTest {
|
|||||||
.isEqualTo("validation.msg.loan.reAge.numberOfInstallments.not.greater.than.zero");
|
.isEqualTo("validation.msg.loan.reAge.numberOfInstallments.not.greater.than.zero");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testValidateReAge_ShouldThrowException_WhenTransactionAmountIsZero() {
|
||||||
|
// given
|
||||||
|
Loan loan = loan();
|
||||||
|
JsonCommand command = makeJsonCommand("""
|
||||||
|
{
|
||||||
|
"externalId": "12345",
|
||||||
|
"dateFormat": "%s",
|
||||||
|
"locale": "en",
|
||||||
|
"startDate": "%s",
|
||||||
|
"frequencyType": "MONTHS",
|
||||||
|
"frequencyNumber": 1,
|
||||||
|
"numberOfInstallments": 1,
|
||||||
|
"transactionAmount": 0
|
||||||
|
}
|
||||||
|
""".formatted(DATE_FORMAT, formatDate(afterMaturity)));
|
||||||
|
// when
|
||||||
|
PlatformApiDataValidationException result = assertThrows(PlatformApiDataValidationException.class,
|
||||||
|
() -> underTest.validateReAge(loan, command));
|
||||||
|
// then
|
||||||
|
assertThat(result).isNotNull();
|
||||||
|
assertThat(result.getGlobalisationMessageCode()).isEqualTo("validation.msg.validation.errors.exist");
|
||||||
|
assertThat(result.getErrors().getFirst().getUserMessageGlobalisationCode())
|
||||||
|
.isEqualTo("validation.msg.loan.reAge.transactionAmount.not.greater.than.zero");
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testValidateReAge_ShouldThrowException_WhenStartDateIsBeforeMaturity() {
|
public void testValidateReAge_ShouldThrowException_WhenStartDateIsBeforeMaturity() {
|
||||||
// given
|
// given
|
||||||
|
|||||||
+8
@@ -1016,6 +1016,11 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
|||||||
|
|
||||||
protected void reAgeLoan(Long loanId, String frequencyType, int frequencyNumber, String startDate, Integer numberOfInstallments,
|
protected void reAgeLoan(Long loanId, String frequencyType, int frequencyNumber, String startDate, Integer numberOfInstallments,
|
||||||
String reAgeInterestHandling) {
|
String reAgeInterestHandling) {
|
||||||
|
reAgeLoan(loanId, frequencyType, frequencyNumber, startDate, numberOfInstallments, reAgeInterestHandling, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void reAgeLoan(Long loanId, String frequencyType, int frequencyNumber, String startDate, Integer numberOfInstallments,
|
||||||
|
String reAgeInterestHandling, Double transactionAmount) {
|
||||||
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
PostLoansLoanIdTransactionsRequest request = new PostLoansLoanIdTransactionsRequest();
|
||||||
request.setDateFormat(DATETIME_PATTERN);
|
request.setDateFormat(DATETIME_PATTERN);
|
||||||
request.setLocale("en");
|
request.setLocale("en");
|
||||||
@@ -1024,6 +1029,9 @@ public abstract class BaseLoanIntegrationTest extends IntegrationTest {
|
|||||||
request.setStartDate(startDate);
|
request.setStartDate(startDate);
|
||||||
request.setNumberOfInstallments(numberOfInstallments);
|
request.setNumberOfInstallments(numberOfInstallments);
|
||||||
request.setReAgeInterestHandling(reAgeInterestHandling);
|
request.setReAgeInterestHandling(reAgeInterestHandling);
|
||||||
|
if (transactionAmount != null) {
|
||||||
|
request.transactionAmount(transactionAmount);
|
||||||
|
}
|
||||||
loanTransactionHelper.reAge(loanId, request);
|
loanTransactionHelper.reAge(loanId, request);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+75
@@ -949,6 +949,81 @@ public class LoanReAgingIntegrationTest extends BaseLoanIntegrationTest {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void test_LoanReAgeTransactionWithTransactionAmount() {
|
||||||
|
AtomicLong createdLoanId = new AtomicLong();
|
||||||
|
|
||||||
|
runAt("01 January 2023", () -> {
|
||||||
|
// Create Client
|
||||||
|
Long clientId = clientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId();
|
||||||
|
|
||||||
|
int numberOfRepayments = 3;
|
||||||
|
int repaymentEvery = 1;
|
||||||
|
|
||||||
|
// Create Loan Product
|
||||||
|
PostLoanProductsRequest product = createOnePeriod30DaysLongNoInterestPeriodicAccrualProductWithAdvancedPaymentAllocation() //
|
||||||
|
.numberOfRepayments(numberOfRepayments) //
|
||||||
|
.repaymentEvery(repaymentEvery) //
|
||||||
|
.installmentAmountInMultiplesOf(null) //
|
||||||
|
.enableDownPayment(true) //
|
||||||
|
.disbursedAmountPercentageForDownPayment(BigDecimal.valueOf(25)) //
|
||||||
|
.enableAutoRepaymentForDownPayment(true) //
|
||||||
|
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS.longValue()); //
|
||||||
|
|
||||||
|
PostLoanProductsResponse loanProductResponse = loanProductHelper.createLoanProduct(product);
|
||||||
|
Long loanProductId = loanProductResponse.getResourceId();
|
||||||
|
|
||||||
|
// Apply and Approve Loan
|
||||||
|
double amount = 1250.0;
|
||||||
|
|
||||||
|
PostLoansRequest applicationRequest = applyLoanRequest(clientId, loanProductId, "01 January 2023", amount, numberOfRepayments)//
|
||||||
|
.transactionProcessingStrategyCode(LoanProductTestBuilder.ADVANCED_PAYMENT_ALLOCATION_STRATEGY)//
|
||||||
|
.repaymentEvery(repaymentEvery)//
|
||||||
|
.loanTermFrequency(numberOfRepayments)//
|
||||||
|
.repaymentFrequencyType(RepaymentFrequencyType.MONTHS)//
|
||||||
|
.loanTermFrequencyType(RepaymentFrequencyType.MONTHS);
|
||||||
|
|
||||||
|
PostLoansResponse postLoansResponse = loanTransactionHelper.applyLoan(applicationRequest);
|
||||||
|
|
||||||
|
PostLoansLoanIdResponse approvedLoanResult = loanTransactionHelper.approveLoan(postLoansResponse.getResourceId(),
|
||||||
|
approveLoanRequest(amount, "01 January 2023"));
|
||||||
|
|
||||||
|
Long loanId = approvedLoanResult.getLoanId();
|
||||||
|
|
||||||
|
// disburse Loan
|
||||||
|
disburseLoan(loanId, BigDecimal.valueOf(1250.0), "01 January 2023");
|
||||||
|
createdLoanId.set(loanId);
|
||||||
|
});
|
||||||
|
|
||||||
|
runAt("12 April 2023", () -> {
|
||||||
|
long loanId = createdLoanId.get();
|
||||||
|
|
||||||
|
// try re-age transaction with transaction amount in Zero
|
||||||
|
CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class,
|
||||||
|
() -> reAgeLoan(loanId, RepaymentFrequencyType.MONTHS_STRING, 1, "12 April 2023", 4,
|
||||||
|
LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.name(), 0.0));
|
||||||
|
assertEquals(400, exception.getResponse().code());
|
||||||
|
assertTrue(exception.getMessage().contains("validation.msg.loan.reAge.transactionAmount.not.greater.than.zero"));
|
||||||
|
|
||||||
|
// try re-age transaction with transaction amount lower than outstanding
|
||||||
|
exception = assertThrows(CallFailedRuntimeException.class, () -> reAgeLoan(loanId, RepaymentFrequencyType.MONTHS_STRING, 1,
|
||||||
|
"12 April 2023", 4, LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.name(), 900.0));
|
||||||
|
assertEquals(403, exception.getResponse().code());
|
||||||
|
assertTrue(exception.getMessage().contains("error.msg.loan.reage.amount.not.match.with.calculated.reage.amount"));
|
||||||
|
|
||||||
|
// try re-age transaction with transaction amount higher than outstanding
|
||||||
|
exception = assertThrows(CallFailedRuntimeException.class, () -> reAgeLoan(loanId, RepaymentFrequencyType.MONTHS_STRING, 1,
|
||||||
|
"12 April 2023", 4, LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.name(), 5000.0));
|
||||||
|
assertEquals(403, exception.getResponse().code());
|
||||||
|
assertTrue(exception.getMessage().contains("error.msg.loan.reage.amount.not.match.with.calculated.reage.amount"));
|
||||||
|
|
||||||
|
reAgeLoan(loanId, RepaymentFrequencyType.MONTHS_STRING, 1, "12 April 2023", 4,
|
||||||
|
LoanReAgeInterestHandlingType.EQUAL_AMORTIZATION_FULL_INTEREST.name(), 937.5);
|
||||||
|
|
||||||
|
checkMaturityDates(loanId, LocalDate.of(2023, 7, 12), LocalDate.of(2023, 7, 12));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
private HashMap<String, Object> getReAgeTemplate(Long loanId) {
|
private HashMap<String, Object> getReAgeTemplate(Long loanId) {
|
||||||
final String GET_REAGE_TEMPLATE_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/template?command=reAge&"
|
final String GET_REAGE_TEMPLATE_URL = "/fineract-provider/api/v1/loans/" + loanId + "/transactions/template?command=reAge&"
|
||||||
+ Utils.TENANT_IDENTIFIER;
|
+ Utils.TENANT_IDENTIFIER;
|
||||||
|
|||||||
Reference in New Issue
Block a user