FINERACT-2080: use enums instead of integers in Loan, LoanProduct and LoanTransaction

This commit is contained in:
mark.vituska
2025-03-20 14:34:51 +01:00
committed by Adam Saghy
parent 8d2db7f80f
commit 993393b519
51 changed files with 467 additions and 291 deletions
@@ -357,13 +357,12 @@ public class ProductToGLAccountMappingWritePlatformServiceImpl implements Produc
@Override
@Transactional
public Map<String, Object> updateLoanProductToGLAccountMapping(final Long loanProductId, final JsonCommand command,
final boolean accountingRuleChanged, final int accountingRuleTypeId) {
final boolean accountingRuleChanged, final AccountingRuleType accountingRuleType) {
/***
* Variable tracks all accounting mapping properties that have been updated
***/
Map<String, Object> changes = new HashMap<>();
final JsonElement element = this.fromApiJsonHelper.parse(command.json());
final AccountingRuleType accountingRuleType = AccountingRuleType.fromInt(accountingRuleTypeId);
/***
* If the accounting rule has been changed, delete all existing mapping for the product and recreate a new set
@@ -21,6 +21,9 @@ package org.apache.fineract.cob.loan;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.cob.data.LoanCOBParameter;
@@ -30,12 +33,17 @@ import org.apache.fineract.cob.data.LoanIdAndLastClosedBusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
@RequiredArgsConstructor
public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdService {
private static final Collection<LoanStatus> NON_CLOSED_LOAN_STATUSES = new ArrayList<>(
Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED, LoanStatus.ACTIVE,
LoanStatus.TRANSFER_IN_PROGRESS, LoanStatus.TRANSFER_ON_HOLD));
private final LoanRepository loanRepository;
private final NamedParameterJdbcTemplate namedParameterJdbcTemplate;
@@ -69,30 +77,32 @@ public class RetrieveAllNonClosedLoanIdServiceImpl implements RetrieveLoanIdServ
@Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDate(LocalDate businessDate, List<Long> loanIds) {
return loanRepository.findAllNonClosedLoansBehindByLoanIds(businessDate, loanIds);
return loanRepository.findAllLoansBehindByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES);
}
@Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsBehindDateOrNull(LocalDate businessDate, List<Long> loanIds) {
return loanRepository.findAllNonClosedLoansBehindOrNullByLoanIds(businessDate, loanIds);
return loanRepository.findAllLoansBehindOrNullByLoanIdsAndStatuses(businessDate, loanIds, NON_CLOSED_LOAN_STATUSES);
}
@Override
public List<LoanIdAndLastClosedBusinessDate> retrieveLoanIdsOldestCobProcessed(LocalDate businessDate) {
return loanRepository.findOldestCOBProcessedLoan(businessDate);
return loanRepository.findOldestCOBProcessedLoan(businessDate, NON_CLOSED_LOAN_STATUSES);
}
@Override
public List<Long> retrieveAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(LoanCOBParameter loanCOBParameter,
boolean isCatchUp) {
if (isCatchUp) {
return loanRepository.findAllNonClosedLoansByLastClosedBusinessDateNotNullAndMinAndMaxLoanId(loanCOBParameter.getMinLoanId(),
loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)
.minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND));
return loanRepository.findAllLoansByLastClosedBusinessDateNotNullAndMinAndMaxLoanIdAndStatuses(
loanCOBParameter.getMinLoanId(), loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil
.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND),
NON_CLOSED_LOAN_STATUSES);
} else {
return loanRepository.findAllNonClosedLoansByLastClosedBusinessDateAndMinAndMaxLoanId(loanCOBParameter.getMinLoanId(),
loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil.getBusinessDateByType(BusinessDateType.COB_DATE)
.minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND));
return loanRepository.findAllLoansByLastClosedBusinessDateAndMinAndMaxLoanIdAndStatuses(
loanCOBParameter.getMinLoanId(), loanCOBParameter.getMaxLoanId(), ThreadLocalContextUtil
.getBusinessDateByType(BusinessDateType.COB_DATE).minusDays(LoanCOBConstant.NUMBER_OF_DAYS_BEHIND),
NON_CLOSED_LOAN_STATUSES);
}
}
@@ -89,7 +89,7 @@ import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.account.exception.DifferentCurrenciesException;
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.exception.LoanNotFoundException;
import org.apache.fineract.portfolio.note.domain.Note;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
@@ -128,7 +128,7 @@ public class InteropServiceImpl implements InteropService {
private final NoteRepository noteRepository;
private final PaymentTypeRepository paymentTypeRepository;
private final InteropIdentifierRepository identifierRepository;
private final LoanRepository loanRepository;
private final LoanRepositoryWrapper loanRepositoryWrapper;
private final SavingsHelper savingsHelper;
private final SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper;
@@ -556,7 +556,7 @@ public class InteropServiceImpl implements InteropService {
}
private Loan validateAndGetLoan(String accountId) {
Loan loan = loanRepository.findNonClosedLoanByAccountNumber(accountId);
Loan loan = loanRepositoryWrapper.findNonClosedLoanByAccountNumber(accountId);
if (loan == null) {
throw new LoanNotFoundException(accountId);
}
@@ -28,7 +28,7 @@ import org.apache.fineract.interoperation.service.InteropService;
import org.apache.fineract.interoperation.service.InteropServiceImpl;
import org.apache.fineract.organisation.monetary.domain.ApplicationCurrencyRepository;
import org.apache.fineract.portfolio.loanaccount.data.LoanAccountData;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.note.domain.NoteRepository;
import org.apache.fineract.portfolio.paymenttype.domain.PaymentTypeRepository;
import org.apache.fineract.portfolio.savings.domain.SavingsAccountRepository;
@@ -49,14 +49,15 @@ public class InteroperationConfiguration {
public InteropService interopService(PlatformSecurityContext securityContext, InteropDataValidator interopDataValidator,
SavingsAccountRepository savingsAccountRepository, SavingsAccountTransactionRepository savingsAccountTransactionRepository,
ApplicationCurrencyRepository applicationCurrencyRepository, NoteRepository noteRepository,
PaymentTypeRepository paymentTypeRepository, InteropIdentifierRepository identifierRepository, LoanRepository loanRepository,
SavingsHelper savingsHelper, SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
PaymentTypeRepository paymentTypeRepository, InteropIdentifierRepository identifierRepository,
LoanRepositoryWrapper loanRepositoryWrapper, SavingsHelper savingsHelper,
SavingsAccountTransactionSummaryWrapper savingsAccountTransactionSummaryWrapper,
SavingsAccountDomainService savingsAccountService, JdbcTemplate jdbcTemplate,
PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService,
DefaultToApiJsonSerializer<LoanAccountData> toApiJsonSerializer, DatabaseSpecificSQLGenerator sqlGenerator) {
return new InteropServiceImpl(securityContext, interopDataValidator, savingsAccountRepository, savingsAccountTransactionRepository,
applicationCurrencyRepository, noteRepository, paymentTypeRepository, identifierRepository, loanRepository, savingsHelper,
savingsAccountTransactionSummaryWrapper, savingsAccountService, jdbcTemplate, commandsSourceWritePlatformService,
toApiJsonSerializer, sqlGenerator);
applicationCurrencyRepository, noteRepository, paymentTypeRepository, identifierRepository, loanRepositoryWrapper,
savingsHelper, savingsAccountTransactionSummaryWrapper, savingsAccountService, jdbcTemplate,
commandsSourceWritePlatformService, toApiJsonSerializer, sqlGenerator);
}
}
@@ -23,6 +23,7 @@ import java.util.List;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.savings.domain.SavingsAccount;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
@@ -52,15 +53,16 @@ public interface CalendarInstanceRepository extends JpaRepository<CalendarInstan
Collection<CalendarInstance> findByCalendarIdAndEntityTypeId(Long calendarId, Integer entityTypeId);
/** Should use in clause, can I do it without creating a new class? **/
@Query("select ci from CalendarInstance ci where ci.entityId in (select loan.id from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId and (loan.loanStatus = 100 or loan.loanStatus = 200 or loan.loanStatus = 300)) and ci.entityTypeId = 3")
List<CalendarInstance> findCalendarInstancesForActiveLoansByGroupIdAndClientId(@Param("groupId") Long groupId,
@Param("clientId") Long clientId);
@Query("select ci from CalendarInstance ci where ci.entityId in (select loan.id from Loan loan where loan.client.id = :clientId and loan.group.id = :groupId and loan.loanStatus in :loanStatuses) and ci.entityTypeId = 3")
List<CalendarInstance> findCalendarInstancesForLoansByGroupIdAndClientIdAndStatuses(@Param("groupId") Long groupId,
@Param("clientId") Long clientId, @Param("loanStatuses") Collection<LoanStatus> loanStatuses);
/**
* EntityType = 3 is for loan
*/
@Query("SELECT COUNT(ci.id) FROM CalendarInstance ci, Loan loan WHERE loan.id = ci.entityId AND ci.entityTypeId = 3 AND ci.calendar.id = :calendarId AND loan.loanStatus IN :loanStatuses ")
Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId, @Param("loanStatuses") Collection<Integer> loanStatuses);
Integer countOfLoansSyncedWithCalendar(@Param("calendarId") Long calendarId,
@Param("loanStatuses") Collection<LoanStatus> loanStatuses);
}
@@ -196,8 +196,8 @@ public class CalendarWritePlatformServiceJpaRepositoryImpl implements CalendarWr
Boolean areActiveEntitiesSynced = false;
final Long calendarId = command.entityId();
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
final Collection<LoanStatus> loanStatuses = new ArrayList<>(
Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED, LoanStatus.ACTIVE));
final Integer numberOfActiveLoansSyncedWithThisCalendar = this.calendarInstanceRepository.countOfLoansSyncedWithCalendar(calendarId,
loanStatuses);
@@ -1065,7 +1065,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
private void handleForeClosureTransactions(final Loan loan, final LoanTransaction repaymentTransaction,
final LoanLifecycleStateMachine loanLifecycleStateMachine, final ScheduleGeneratorDTO scheduleGeneratorDTO) {
loan.setLoanSubStatus(LoanSubStatus.FORECLOSED.getValue());
loan.setLoanSubStatus(LoanSubStatus.FORECLOSED);
loanDownPaymentHandlerService.handleRepaymentOrRecoveryOrWaiverTransaction(loan, repaymentTransaction, loanLifecycleStateMachine,
null, scheduleGeneratorDTO);
}
@@ -27,6 +27,8 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccrualActivityRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionType;
import org.apache.fineract.portfolio.loanaccount.service.LoanAccrualActivityProcessingService;
import org.springframework.batch.core.StepContribution;
import org.springframework.batch.core.scope.context.ChunkContext;
@@ -46,7 +48,8 @@ public class AccrualActivityPostingTasklet implements Tasklet {
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
final LocalDate yesterday = DateUtils.getBusinessLocalDate().minusDays(1);
List<Throwable> errors = new ArrayList<>();
Set<Long> loanAccounts = loanAccrualActivityRepository.fetchLoanIdsForAccrualActivityPosting(yesterday);
Set<Long> loanAccounts = loanAccrualActivityRepository.fetchLoanIdsForAccrualActivityPosting(yesterday,
LoanTransactionType.ACCRUAL_ACTIVITY, LoanStatus.ACTIVE);
for (Long accountId : loanAccounts) {
try {
loanAccrualActivityProcessingService.makeAccrualActivityTransaction(accountId, yesterday);
@@ -68,8 +68,8 @@ public class ApplyHolidaysToLoansTasklet implements Tasklet {
return RepeatStatus.FINISHED;
}
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
final Collection<LoanStatus> loanStatuses = new ArrayList<>(
Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED, LoanStatus.ACTIVE));
final List<Holiday> holidays = holidayRepository.findUnprocessed();
for (final Holiday holiday : holidays) {
@@ -210,7 +210,7 @@ public final class LoanApplicationValidator {
expectedFirstRepaymentOnDate);
}
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType(),
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(),
loan.repaymentScheduleDetail().getNumberOfRepayments(), loan.repaymentScheduleDetail().getRepayEvery(),
loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType().getValue(), loan);
}
@@ -224,7 +224,7 @@ public final class LoanApplicationValidator {
expectedFirstRepaymentOnDate);
}
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType(),
validateLoanTermAndRepaidEveryValues(loan.getTermFrequency(), loan.getTermPeriodFrequencyType().getValue(),
loan.repaymentScheduleDetail().getNumberOfRepayments(), loan.repaymentScheduleDetail().getRepayEvery(),
loan.repaymentScheduleDetail().getRepaymentPeriodFrequencyType().getValue(), loan);
}
@@ -1850,11 +1850,9 @@ public final class LoanApplicationValidator {
final Long clientId = this.fromApiJsonHelper.extractLongNamed(LoanApiConstants.clientIdParameterName, element);
if (groupId != null) {
activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByGroup(groupId,
LoanStatus.ACTIVE.getValue());
activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByGroup(groupId, LoanStatus.ACTIVE);
} else {
activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByClient(clientId,
LoanStatus.ACTIVE.getValue());
activeLoansLoanProductIds = this.loanRepositoryWrapper.findActiveLoansLoanProductIdsByClient(clientId, LoanStatus.ACTIVE);
}
checkForProductMixRestrictions(activeLoansLoanProductIds, productId);
}
@@ -56,40 +56,36 @@ public abstract class CommonLoanSummaryDataProvider implements LoanSummaryDataPr
BigDecimal totalUnpaidPayableDueInterest = BigDecimal.ZERO;
BigDecimal totalUnpaidPayableNotDueInterest = BigDecimal.ZERO;
totalChargeAdjustment = fetchLoanTransactionBalanceByType(loanTransactionBalances,
LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
totalChargeAdjustment = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.CHARGE_ADJUSTMENT);
totalChargeAdjustmentReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.CHARGE_ADJUSTMENT.getValue());
LoanTransactionType.CHARGE_ADJUSTMENT);
totalChargeback = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.CHARGEBACK.getValue());
totalChargeback = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.CHARGEBACK);
totalCreditBalanceRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances,
LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
totalCreditBalanceRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.CREDIT_BALANCE_REFUND);
totalCreditBalanceRefundReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.CREDIT_BALANCE_REFUND.getValue());
LoanTransactionType.CREDIT_BALANCE_REFUND);
totalGoodwillCredit = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.GOODWILL_CREDIT.getValue());
totalGoodwillCredit = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.GOODWILL_CREDIT);
totalGoodwillCreditReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.GOODWILL_CREDIT.getValue());
LoanTransactionType.GOODWILL_CREDIT);
totalInterestRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.INTEREST_REFUND.getValue());
totalInterestRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.INTEREST_REFUND);
totalInterestPaymentWaiver = fetchLoanTransactionBalanceByType(loanTransactionBalances,
LoanTransactionType.INTEREST_PAYMENT_WAIVER.getValue());
LoanTransactionType.INTEREST_PAYMENT_WAIVER);
totalMerchantRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances,
LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
totalMerchantRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.MERCHANT_ISSUED_REFUND);
totalMerchantRefundReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.MERCHANT_ISSUED_REFUND.getValue());
LoanTransactionType.MERCHANT_ISSUED_REFUND);
totalPayoutRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.PAYOUT_REFUND.getValue());
totalPayoutRefundReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.PAYOUT_REFUND.getValue());
totalPayoutRefund = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.PAYOUT_REFUND);
totalPayoutRefundReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances, LoanTransactionType.PAYOUT_REFUND);
totalRepaymentTransaction = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.REPAYMENT.getValue())
.add(fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.DOWN_PAYMENT.getValue()));
totalRepaymentTransaction = fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.REPAYMENT)
.add(fetchLoanTransactionBalanceByType(loanTransactionBalances, LoanTransactionType.DOWN_PAYMENT));
totalRepaymentTransactionReversed = fetchLoanTransactionBalanceReversedByType(loanTransactionBalances,
LoanTransactionType.REPAYMENT.getValue());
LoanTransactionType.REPAYMENT);
if (repaymentSchedule != null) {
// Outstanding Interest on Past due installments
@@ -142,14 +138,14 @@ public abstract class CommonLoanSummaryDataProvider implements LoanSummaryDataPr
}
private static BigDecimal fetchLoanTransactionBalanceByType(final Collection<LoanTransactionBalance> loanTransactionBalances,
final Integer transactionType) {
final LoanTransactionType transactionType) {
final Optional<LoanTransactionBalance> optLoanTransactionBalance = loanTransactionBalances.stream()
.filter(balance -> balance.getTransactionType().equals(transactionType) && !balance.isReversed()).findFirst();
return optLoanTransactionBalance.isPresent() ? optLoanTransactionBalance.get().getAmount() : BigDecimal.ZERO;
}
private static BigDecimal fetchLoanTransactionBalanceReversedByType(final Collection<LoanTransactionBalance> loanTransactionBalances,
final Integer transactionType) {
final LoanTransactionType transactionType) {
final Optional<LoanTransactionBalance> optLoanTransactionBalance = loanTransactionBalances.stream()
.filter(balance -> balance.getTransactionType().equals(transactionType) && balance.isReversed()
&& balance.isManuallyAdjustedOrReversed())
@@ -147,8 +147,8 @@ public class LoanAccrualActivityProcessingServiceImpl implements LoanAccrualActi
if (MathUtil.isGreaterThanZero(feeChargesPortion) || MathUtil.isGreaterThanZero(penaltyChargesPortion)
|| MathUtil.isGreaterThanZero(interestPortion)) {
BigDecimal transactionAmount = MathUtil.add(feeChargesPortion, penaltyChargesPortion, interestPortion);
LoanTransaction newActivity = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.ACCRUAL_ACTIVITY.getValue(),
closureDate, transactionAmount, null, interestPortion, feeChargesPortion, penaltyChargesPortion, null, false, null,
LoanTransaction newActivity = new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.ACCRUAL_ACTIVITY, closureDate,
transactionAmount, null, interestPortion, feeChargesPortion, penaltyChargesPortion, null, false, null,
externalIdFactory.create());
makeAccrualActivityTransaction(loan, newActivity);
}
@@ -106,7 +106,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
@Override
@Transactional
public void addPeriodicAccruals(@NotNull LocalDate tillDate) throws JobExecutionException {
List<Loan> loans = loanRepositoryWrapper.findLoansForPeriodicAccrual(AccountingRuleType.ACCRUAL_PERIODIC.getValue(), tillDate,
List<Loan> loans = loanRepositoryWrapper.findLoansForPeriodicAccrual(AccountingRuleType.ACCRUAL_PERIODIC, tillDate,
!isChargeOnDueDate());
List<Throwable> errors = new ArrayList<>();
for (Loan loan : loans) {
@@ -141,7 +141,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
@Override
@Transactional
public void addAccruals(@NotNull LocalDate tillDate) throws JobExecutionException {
List<Loan> loans = loanRepositoryWrapper.findLoansForAddAccrual(AccountingRuleType.ACCRUAL_PERIODIC.getValue(), tillDate,
List<Loan> loans = loanRepositoryWrapper.findLoansForAddAccrual(AccountingRuleType.ACCRUAL_PERIODIC, tillDate,
!isChargeOnDueDate());
List<Throwable> errors = new ArrayList<>();
for (Loan loan : loans) {
@@ -61,6 +61,7 @@ import org.apache.fineract.portfolio.charge.domain.Charge;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper;
import org.apache.fineract.portfolio.collateralmanagement.service.LoanCollateralAssembler;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.fund.domain.Fund;
import org.apache.fineract.portfolio.fund.domain.FundRepository;
import org.apache.fineract.portfolio.fund.exception.FundNotFoundException;
@@ -720,10 +721,10 @@ public class LoanAssemblerImpl implements LoanAssembler {
}
if (command.isChangeInIntegerParameterNamed(LoanApiConstants.loanTermFrequencyTypeParameterName,
loan.getTermPeriodFrequencyType())) {
loan.getTermPeriodFrequencyType().getValue())) {
final Integer newValue = command.integerValueOfParameterNamed(LoanApiConstants.loanTermFrequencyTypeParameterName);
changes.put(LoanApiConstants.loanTermFrequencyTypeParameterName, newValue);
loan.setTermPeriodFrequencyType(newValue);
loan.setTermPeriodFrequencyType(PeriodFrequencyType.fromInt(newValue));
}
if (command.isChangeInBigDecimalParameterNamed(LoanApiConstants.principalParameterName, loan.getApprovedPrincipal())) {
@@ -78,8 +78,8 @@ public class LoanTransactionAssembler {
BigDecimal penaltyChargesPortion = installment.getPenaltyCharges();
BigDecimal transactionAmount = MathUtil.add(interestPortion, feeChargesPortion, penaltyChargesPortion);
return MathUtil.isGreaterThanZero(transactionAmount)
? new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.ACCRUAL_ACTIVITY.getValue(), transactionDate,
transactionAmount, null, interestPortion, feeChargesPortion, penaltyChargesPortion, null, false, null, externalId)
? new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.ACCRUAL_ACTIVITY, transactionDate, transactionAmount,
null, interestPortion, feeChargesPortion, penaltyChargesPortion, null, false, null, externalId)
: null;
}
}
@@ -1003,7 +1003,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
loan.setClosedOnDate(transactionDate);
loan.setActualMaturityDate(transactionDate);
loanLifecycleStateMachine.transition(LoanEvent.REPAID_IN_FULL, loan);
} else if (LoanStatus.fromInt(loan.getLoanStatus()).isOverpaid()) {
} else if (loan.getLoanStatus().isOverpaid()) {
if (loan.getTotalOverpaid() == null || BigDecimal.ZERO.compareTo(loan.getTotalOverpaid()) == 0) {
loan.setOverpaidOnDate(null);
}
@@ -1306,8 +1306,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
.orElseThrow(() -> new LoanTransactionNotFoundException(command.entityId(), command.getLoanId()));
Loan loan = this.loanAssembler.assembleFrom(loanId);
if (loan.getStatus().isClosed() && loan.getLoanSubStatus() != null
&& loan.getLoanSubStatus().equals(LoanSubStatus.FORECLOSED.getValue())) {
if (loan.getStatus().isClosed() && loan.getLoanSubStatus() != null && loan.getLoanSubStatus().equals(LoanSubStatus.FORECLOSED)) {
final String defaultUserMessage = "The loan cannot reopened as it is foreclosed.";
throw new LoanForeclosureException("loan.cannot.be.reopened.as.it.is.foreclosured", defaultUserMessage, loanId);
}
@@ -2067,9 +2066,9 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
final WorkingDays workingDays = this.workingDaysRepository.findOne();
final List<Long> existingTransactionIds = new ArrayList<>();
final List<Long> existingReversedTransactionIds = new ArrayList<>();
final Collection<Integer> loanStatuses = new ArrayList<>(Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL.getValue(),
LoanStatus.APPROVED.getValue(), LoanStatus.ACTIVE.getValue()));
final Collection<Integer> loanTypes = new ArrayList<>(Arrays.asList(AccountType.GROUP.getValue(), AccountType.JLG.getValue()));
final Collection<LoanStatus> loanStatuses = new ArrayList<>(
Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED, LoanStatus.ACTIVE));
final Collection<AccountType> loanTypes = new ArrayList<>(Arrays.asList(AccountType.GROUP, AccountType.JLG));
final Collection<Long> loanIds = new ArrayList<>(loanCalendarInstances.size());
// loop through loanCalendarInstances to get loan ids
for (final CalendarInstance calendarInstance : loanCalendarInstances) {
@@ -2134,10 +2133,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loan.isGroupLoan()) {
if (loan.loanProduct().isIncludeInBorrowerCycle()) {
loansToUpdate = this.loanRepositoryWrapper.getGroupLoansToUpdateLoanCounter(loan.getCurrentLoanCounter(), loan.getGroupId(),
AccountType.GROUP.getValue());
AccountType.GROUP);
} else {
loansToUpdate = this.loanRepositoryWrapper.getGroupLoansToUpdateLoanProductCounter(loan.getLoanProductLoanCounter(),
loan.getGroupId(), AccountType.GROUP.getValue());
loan.getGroupId(), AccountType.GROUP);
}
} else {
@@ -2162,7 +2161,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
if (loan.isGroupLoan()) {
final List<Loan> loansToUpdateForLoanCounter = this.loanRepositoryWrapper.getGroupLoansDisbursedAfter(actualDisbursementDate,
loan.getGroupId(), AccountType.GROUP.getValue());
loan.getGroupId(), AccountType.GROUP);
final Integer newLoanCounter = getNewGroupLoanCounter(loan);
final Integer newLoanProductCounter = getNewGroupLoanProductCounter(loan);
updateLoanCounter(loan, loansToUpdateForLoanCounter, newLoanCounter, newLoanProductCounter);
@@ -2177,7 +2176,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private Integer getNewGroupLoanCounter(final Loan loan) {
Integer maxClientLoanCounter = this.loanRepositoryWrapper.getMaxGroupLoanCounter(loan.getGroupId(), AccountType.GROUP.getValue());
Integer maxClientLoanCounter = this.loanRepositoryWrapper.getMaxGroupLoanCounter(loan.getGroupId(), AccountType.GROUP);
if (maxClientLoanCounter == null) {
maxClientLoanCounter = 1;
} else {
@@ -2189,7 +2188,7 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
private Integer getNewGroupLoanProductCounter(final Loan loan) {
Integer maxLoanProductLoanCounter = this.loanRepositoryWrapper.getMaxGroupLoanProductCounter(loan.loanProduct().getId(),
loan.getGroupId(), AccountType.GROUP.getValue());
loan.getGroupId(), AccountType.GROUP);
if (maxLoanProductLoanCounter == null) {
maxLoanProductLoanCounter = 1;
} else {
@@ -63,18 +63,16 @@ public class ProgressiveLoanInterestRefundServiceImpl implements InterestRefundS
private static void simulateRepaymentForDisbursements(LoanTransaction lt, final AtomicReference<BigDecimal> refundFinal,
List<LoanTransaction> collect) {
collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf().getValue(), lt.getDateOf(), lt.getAmount(),
collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), lt.getTypeOf(), lt.getDateOf(), lt.getAmount(),
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
if (lt.getTypeOf().isDisbursement() && MathUtil.isGreaterThanZero(refundFinal.get())) {
if (lt.getAmount().compareTo(refundFinal.get()) <= 0) {
collect.add(
new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), lt.getAmount(),
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT, lt.getDateOf(), lt.getAmount(),
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
refundFinal.set(refundFinal.get().subtract(lt.getAmount()));
} else {
collect.add(
new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT.getValue(), lt.getDateOf(), refundFinal.get(),
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
collect.add(new LoanTransaction(lt.getLoan(), lt.getLoan().getOffice(), REPAYMENT, lt.getDateOf(), refundFinal.get(),
BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, BigDecimal.ZERO, false, null, null));
refundFinal.set(BigDecimal.ZERO);
}
}
@@ -176,8 +176,8 @@ public class LoanReAgingServiceImpl {
Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate);
BigDecimal txPrincipalAmount = txPrincipal.getAmount();
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE.getValue(), transactionDate, txPrincipalAmount,
txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId);
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAGE, transactionDate, txPrincipalAmount, txPrincipalAmount,
ZERO, ZERO, ZERO, null, false, null, txExternalId);
}
private LoanReAgeParameter createReAgeParameter(LoanTransaction reAgeTransaction, JsonCommand command) {
@@ -156,7 +156,7 @@ public class LoanReAmortizationServiceImpl {
Money txPrincipal = loan.getTotalPrincipalOutstandingUntil(transactionDate);
BigDecimal txPrincipalAmount = txPrincipal.getAmount();
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAMORTIZE.getValue(), transactionDate, txPrincipalAmount,
return new LoanTransaction(loan, loan.getOffice(), LoanTransactionType.REAMORTIZE, transactionDate, txPrincipalAmount,
txPrincipalAmount, ZERO, ZERO, ZERO, null, false, null, txExternalId);
}
}
@@ -1704,8 +1704,8 @@ public final class LoanProductDataValidator {
}
if (actualValue) {
Integer ruleType = accountingRuleType;
if (ruleType == null) {
ruleType = loanProduct.getAccountingRule();
if (ruleType == null && loanProduct.getAccountingRule() != null) {
ruleType = loanProduct.getAccountingRule().getValue();
}
if (!AccountingValidations.isAccrualBasedAccounting(ruleType)) {
baseDataValidator.reset().parameter(LoanProductConstants.ENABLE_ACCRUAL_ACTIVITY_POSTING)
@@ -22,6 +22,8 @@ import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
@@ -52,6 +54,7 @@ import org.apache.fineract.portfolio.group.exception.ClientNotInGroupException;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepositoryWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.service.LoanOfficerService;
import org.apache.fineract.portfolio.loanaccount.service.LoanWritePlatformService;
import org.apache.fineract.portfolio.note.service.NoteWritePlatformService;
@@ -151,8 +154,10 @@ public class TransferWritePlatformServiceJpaRepositoryImpl implements TransferWr
final CalendarInstance sourceGroupCalendarInstance = this.calendarInstanceRepository.findByEntityIdAndEntityTypeIdAndCalendarTypeId(
sourceGroup.getId(), CalendarEntityType.GROUPS.getValue(), CalendarType.COLLECTION.getValue());
// get all customer loans synced with this group calendar Instance
final Collection<LoanStatus> activeLoanStatuses = new ArrayList<>(
Arrays.asList(LoanStatus.SUBMITTED_AND_PENDING_APPROVAL, LoanStatus.APPROVED, LoanStatus.ACTIVE));
final List<CalendarInstance> activeLoanCalendarInstances = this.calendarInstanceRepository
.findCalendarInstancesForActiveLoansByGroupIdAndClientId(sourceGroup.getId(), client.getId());
.findCalendarInstancesForLoansByGroupIdAndClientIdAndStatuses(sourceGroup.getId(), client.getId(), activeLoanStatuses);
/**
* if a calendar is present in the source group along with loans synced with it, we should ensure that the
@@ -337,7 +337,7 @@ public class LoanAccountDelinquencyRangeEventSerializerTest {
delinquencyEffectivePauseHelper, configurationDomainService);
Loan loan = Mockito.spy(Loan.class);
ReflectionTestUtils.setField(loan, "loanStatus", 300);
ReflectionTestUtils.setField(loan, "loanStatus", LoanStatus.ACTIVE);
LoanTransaction transaction1 = Mockito.mock(LoanTransaction.class);
LoanTransaction transaction2 = Mockito.mock(LoanTransaction.class);
CollectionData collectionData = Mockito.mock(CollectionData.class);
@@ -154,7 +154,7 @@ public class LoanDelinquencyDomainServiceTest {
when(loanProductRelatedDetail.getGraceOnArrearsAgeing()).thenReturn(0);
when(loan.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK.getValue()))
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK))
.thenReturn(Collections.emptyList());
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
when(loan.getCurrency()).thenReturn(currency);
@@ -223,7 +223,7 @@ public class LoanDelinquencyDomainServiceTest {
when(loanProductRelatedDetail.getGraceOnArrearsAgeing()).thenReturn(0);
when(loan.getLoanProductRelatedDetail()).thenReturn(loanProductRelatedDetail);
when(loan.getRepaymentScheduleInstallments()).thenReturn(repaymentScheduleInstallments);
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK.getValue()))
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK))
.thenReturn(Collections.emptyList());
when(loan.getLastLoanRepaymentScheduleInstallment()).thenReturn(repaymentScheduleInstallments.get(0));
when(loan.getCurrency()).thenReturn(currency);
@@ -279,7 +279,7 @@ public class LoanDelinquencyDomainServiceTest {
when(loan.isEnableInstallmentLevelDelinquency()).thenReturn(true);
when(loan.getCurrency()).thenReturn(currency);
when(loan.getStatus()).thenReturn(LoanStatus.ACTIVE);
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK.getValue()))
when(loanTransactionReadService.fetchLoanTransactionsByType(loan.getId(), null, LoanTransactionType.CHARGEBACK))
.thenReturn(Arrays.asList(loanTransaction));
when(delinquencyEffectivePauseHelper.getPausedDaysBeforeDate(effectiveDelinquencyList, businessDate)).thenReturn(0L);
@@ -142,7 +142,6 @@ class DefaultLoanLifecycleStateMachineTest {
Loan loan = Mockito.mock(Loan.class);
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
Mockito.when(loan.getCurrency()).thenReturn(currency);
Mockito.when(loan.getPlainStatus()).thenReturn(LoanStatus.OVERPAID.getValue());
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.OVERPAID);
Mockito.when(loan.getTotalOverpaidAsMoney()).thenReturn(zero);
Mockito.when(loan.getSummary()).thenReturn(loanSummary);
@@ -150,7 +149,7 @@ class DefaultLoanLifecycleStateMachineTest {
// when
underTest.transition(LoanEvent.LOAN_DISBURSED, loan);
// then
verify(loan, Mockito.times(1)).setLoanStatus(LoanStatus.ACTIVE.getValue());
verify(loan, Mockito.times(1)).setLoanStatus(LoanStatus.ACTIVE);
verify(businessEventNotifierService).notifyPostBusinessEvent(any(LoanStatusChangedBusinessEvent.class));
}
@@ -162,7 +161,6 @@ class DefaultLoanLifecycleStateMachineTest {
Loan loan = Mockito.mock(Loan.class);
LoanSummary loanSummary = Mockito.mock(LoanSummary.class);
Mockito.when(loan.getCurrency()).thenReturn(currency);
Mockito.when(loan.getPlainStatus()).thenReturn(LoanStatus.OVERPAID.getValue());
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.OVERPAID);
Mockito.when(loan.getTotalOverpaidAsMoney()).thenReturn(zero);
Mockito.when(loan.getSummary()).thenReturn(loanSummary);
@@ -170,7 +168,7 @@ class DefaultLoanLifecycleStateMachineTest {
// when
underTest.transition(LoanEvent.LOAN_DISBURSED, loan);
// then
verify(loan, Mockito.times(1)).setLoanStatus(LoanStatus.CLOSED_OBLIGATIONS_MET.getValue());
verify(loan, Mockito.times(1)).setLoanStatus(LoanStatus.CLOSED_OBLIGATIONS_MET);
verify(businessEventNotifierService).notifyPostBusinessEvent(any(LoanStatusChangedBusinessEvent.class));
}
@@ -179,13 +177,12 @@ class DefaultLoanLifecycleStateMachineTest {
// given
Money overpayment = Money.of(new MonetaryCurrency("USD", 2, null), BigDecimal.TEN);
Loan loan = Mockito.mock(Loan.class);
Mockito.when(loan.getPlainStatus()).thenReturn(LoanStatus.OVERPAID.getValue());
Mockito.when(loan.getStatus()).thenReturn(LoanStatus.OVERPAID);
Mockito.when(loan.getTotalOverpaidAsMoney()).thenReturn(overpayment);
// when
underTest.transition(LoanEvent.LOAN_DISBURSED, loan);
// then
verify(loan, Mockito.never()).setLoanStatus(LoanStatus.ACTIVE.getValue());
verify(loan, Mockito.never()).setLoanStatus(LoanStatus.ACTIVE);
verify(businessEventNotifierService, Mockito.never()).notifyPostBusinessEvent(any(LoanStatusChangedBusinessEvent.class));
}
@@ -422,9 +419,7 @@ class DefaultLoanLifecycleStateMachineTest {
private Loan createLoanWithStatus(LoanStatus status) {
Loan result = new Loan();
if (status != null) {
result.setLoanStatus(status.getValue());
}
result.setLoanStatus(status);
return result;
}
}
@@ -208,40 +208,40 @@ public class LoanTest {
LoanTransaction lt1 = new LoanTransaction();
ReflectionTestUtils.setField(lt1, "id", 1L);
ReflectionTestUtils.setField(lt1, "typeOf", LoanTransactionType.DISBURSEMENT.getValue());
ReflectionTestUtils.setField(lt1, "typeOf", LoanTransactionType.DISBURSEMENT);
ReflectionTestUtils.setField(lt1, "dateOf", today);
ReflectionTestUtils.setField(lt1, "createdDate", now);
LoanTransaction lt2 = new LoanTransaction();
ReflectionTestUtils.setField(lt2, "id", 2L);
ReflectionTestUtils.setField(lt2, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt2, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER);
ReflectionTestUtils.setField(lt2, "dateOf", today);
ReflectionTestUtils.setField(lt2, "createdDate", now);
LoanTransaction lt3 = new LoanTransaction();
ReflectionTestUtils.setField(lt3, "id", 3L);
ReflectionTestUtils.setField(lt3, "typeOf", LoanTransactionType.REPAYMENT.getValue());
ReflectionTestUtils.setField(lt3, "typeOf", LoanTransactionType.REPAYMENT);
ReflectionTestUtils.setField(lt3, "dateOf", today);
ReflectionTestUtils.setField(lt3, "createdDate", now);
ReflectionTestUtils.setField(lt3, "reversed", true);
LoanTransaction lt4 = new LoanTransaction();
ReflectionTestUtils.setField(lt4, "id", 4L);
ReflectionTestUtils.setField(lt4, "typeOf", LoanTransactionType.WAIVE_INTEREST.getValue());
ReflectionTestUtils.setField(lt4, "typeOf", LoanTransactionType.WAIVE_INTEREST);
ReflectionTestUtils.setField(lt4, "dateOf", today);
ReflectionTestUtils.setField(lt4, "createdDate", now);
LoanTransaction lt5 = new LoanTransaction();
ReflectionTestUtils.setField(lt5, "id", 5L);
ReflectionTestUtils.setField(lt5, "typeOf", LoanTransactionType.INCOME_POSTING.getValue());
ReflectionTestUtils.setField(lt5, "typeOf", LoanTransactionType.INCOME_POSTING);
ReflectionTestUtils.setField(lt5, "dateOf", today);
ReflectionTestUtils.setField(lt5, "createdDate", now);
LoanTransaction lt6 = new LoanTransaction();
ReflectionTestUtils.setField(lt6, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt6, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER);
ReflectionTestUtils.setField(lt6, "dateOf", today.minusDays(2));
LoanTransaction lt7 = new LoanTransaction();
ReflectionTestUtils.setField(lt7, "id", 7L);
ReflectionTestUtils.setField(lt7, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt7, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER);
ReflectionTestUtils.setField(lt7, "dateOf", today.minusDays(2));
LoanTransaction lt8 = new LoanTransaction();
ReflectionTestUtils.setField(lt8, "id", 8L);
ReflectionTestUtils.setField(lt8, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER.getValue());
ReflectionTestUtils.setField(lt8, "typeOf", LoanTransactionType.WITHDRAW_TRANSFER);
ReflectionTestUtils.setField(lt8, "dateOf", today.minusDays(2));
ReflectionTestUtils.setField(lt8, "createdDate", now.minusMinutes(2));