FINERACT-2080: Extract complex loan actions out from Loan entity

This commit is contained in:
budaidev
2025-05-12 10:24:26 +02:00
committed by Adam Saghy
parent ec566b7166
commit 788cd7aff7
14 changed files with 537 additions and 501 deletions
@@ -397,7 +397,7 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
transactionDate, txnExternalId, loanTransactionType);
if (loanTransactionType.isRepaymentAtDisbursement()) {
loan.handlePayDisbursementTransaction(chargeId, newPaymentTransaction, existingTransactionIds, existingReversedTransactionIds);
handlePayDisbursementTransaction(loan, chargeId, newPaymentTransaction, existingTransactionIds, existingReversedTransactionIds);
} else {
final boolean allowTransactionsOnHoliday = this.configurationDomainService.allowTransactionsOnHolidayEnabled();
final List<Holiday> holidays = this.holidayRepository.findByOfficeIdAndGreaterThanDate(loan.getOfficeId(), transactionDate,
@@ -438,6 +438,26 @@ public class LoanAccountDomainServiceJpa implements LoanAccountDomainService {
return newPaymentTransaction;
}
private void handlePayDisbursementTransaction(final Loan loan, final Long chargeId, final LoanTransaction chargesPayment,
final List<Long> existingTransactionIds, final List<Long> existingReversedTransactionIds) {
existingTransactionIds.addAll(loan.findExistingTransactionIds());
existingReversedTransactionIds.addAll(loan.findExistingReversedTransactionIds());
LoanCharge charge = null;
for (final LoanCharge loanCharge : loan.getCharges()) {
if (loanCharge.isActive() && chargeId.equals(loanCharge.getId())) {
charge = loanCharge;
}
}
final LoanChargePaidBy loanChargePaidBy = new LoanChargePaidBy(chargesPayment, charge, charge.amount(), null);
chargesPayment.getLoanChargesPaid().add(loanChargePaidBy);
final Money zero = Money.zero(loan.getCurrency());
chargesPayment.updateComponents(zero, zero, charge.getAmount(loan.getCurrency()), zero);
chargesPayment.updateLoan(loan);
loan.addLoanTransaction(chargesPayment);
loan.updateLoanOutstandingBalances();
charge.markAsFullyPaid();
}
private void postJournalEntries(final Loan loanAccount, final List<Long> existingTransactionIds,
final List<Long> existingReversedTransactionIds, boolean isAccountTransfer) {
postJournalEntries(loanAccount, existingTransactionIds, existingReversedTransactionIds, isAccountTransfer, false);
@@ -112,6 +112,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
private final ThreadPoolTaskExecutor taskExecutor;
private final TransactionTemplate transactionTemplate;
private final LoanAccountingBridgeMapper loanAccountingBridgeMapper;
private final LoanChargeService loanChargeService;
/**
* method adds accrual for batch job "Add Periodic Accrual Transactions" and add accruals api for Loan
@@ -733,7 +734,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
continue;
}
final BigDecimal chargeAmount = MathUtil.toBigDecimal(chargePortion);
final LoanCharge loanCharge = loan.fetchLoanChargesById(accrualCharge.getLoanChargeId());
final LoanCharge loanCharge = loanChargeService.fetchLoanChargesById(loan, accrualCharge.getLoanChargeId());
final LoanChargePaidBy paidBy = new LoanChargePaidBy(transaction, loanCharge, chargeAmount, installment.getInstallmentNumber());
loanCharge.getLoanChargePaidBySet().add(paidBy);
transaction.getLoanChargesPaid().add(paidBy);
@@ -845,7 +846,7 @@ public class LoanAccrualsProcessingServiceImpl implements LoanAccrualsProcessing
Money chargeAmount = loanCharge.getAmount(loan.getCurrency());
if (chargeAmount.isNotEqualTo(accrualTransaction.getAmount(loan.getCurrency()))) {
accrualTransaction.reverse();
loan.handleChargeAppliedTransaction(loanCharge, accrualTransaction.getTransactionDate());
loanChargeService.handleChargeAppliedTransaction(loan, loanCharge, accrualTransaction.getTransactionDate());
}
}
}
@@ -832,7 +832,7 @@ public class LoanAssemblerImpl implements LoanAssembler {
final String chargesParamName = "charges";
if (changes.containsKey(chargesParamName)) {
loan.updateLoanCharges(possiblyModifiedLoanCharges);
loanChargeService.updateLoanCharges(loan, possiblyModifiedLoanCharges);
}
// update installment level delinquency
@@ -296,8 +296,8 @@ public class LoanChargeAssembler {
if (percentage == null) {
percentage = chargeDefinition.getAmount();
}
loanCharge = loan.calculatePerInstallmentChargeAmount(ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation()),
percentage);
loanCharge = LoanCharge.calculatePerInstallmentChargeAmount(loan,
ChargeCalculationType.fromInt(chargeDefinition.getChargeCalculation()), percentage);
}
// If charge type is specified due date and loan is multi disburment
@@ -474,7 +474,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
final Map<String, Object> changes = new LinkedHashMap<>(3);
if (loan.getActiveCharges().contains(loanCharge)) {
final BigDecimal amount = loan.calculateAmountPercentageAppliedTo(loanCharge);
final BigDecimal amount = loanChargeService.calculateAmountPercentageAppliedTo(loan, loanCharge);
final Map<String, Object> loanChargeChanges = loanCharge.update(command, amount);
changes.putAll(loanChargeChanges);
loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement());
@@ -1115,7 +1115,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
// the loan product uses Upfront Accruals, or only when the loan are closed too,
if ((loan.getStatus().isActive() && loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct())
|| loan.getStatus().isOverpaid() || loan.getStatus().isClosedObligationsMet()) {
final LoanTransaction applyLoanChargeTransaction = loan.handleChargeAppliedTransaction(loanCharge, null);
final LoanTransaction applyLoanChargeTransaction = loanChargeService.handleChargeAppliedTransaction(loan, loanCharge, null);
if (applyLoanChargeTransaction != null) {
this.loanTransactionRepository.saveAndFlush(applyLoanChargeTransaction);
businessEventNotifierService
@@ -1123,7 +1123,7 @@ public class LoanChargeWritePlatformServiceImpl implements LoanChargeWritePlatfo
}
} else if (configurationDomainService.isImmediateChargeAccrualPostMaturityEnabled()
&& DateUtils.getBusinessLocalDate().isAfter(loan.getMaturityDate())) {
final LoanTransaction loanTransaction = loan.createChargeAppliedTransaction(loanCharge, null);
final LoanTransaction loanTransaction = loanChargeService.createChargeAppliedTransaction(loan, loanCharge, null);
this.loanTransactionRepository.saveAndFlush(loanTransaction);
businessEventNotifierService.notifyPostBusinessEvent(new LoanAccrualTransactionCreatedBusinessEvent(loanTransaction));
}
@@ -204,7 +204,7 @@ public class LoanDisbursementService {
}
} else if (disbursedOn.equals(loan.getActualDisbursementDate())
&& loan.isNoneOrCashOrUpfrontAccrualAccountingEnabledOnLoanProduct()) {
loan.handleChargeAppliedTransaction(charge, disbursedOn);
loanChargeService.handleChargeAppliedTransaction(loan, charge, disbursedOn);
}
}
@@ -273,7 +273,7 @@ public class LoanDisbursementService {
} else {
if (!loanChargeIds.isEmpty() && loanChargeIds.size() != chargeIdLength) {
for (Long chargeId : loanChargeIds) {
final LoanCharge deleteCharge = loan.fetchLoanChargesById(chargeId);
final LoanCharge deleteCharge = loanChargeService.fetchLoanChargesById(loan, chargeId);
if (loan.getCharges().contains(deleteCharge)) {
loanChargeValidator.validateLoanIsNotClosed(loan, deleteCharge);
loanChargeValidator.validateLoanChargeIsNotWaived(loan, deleteCharge);
@@ -530,7 +530,7 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
final ApplicationCurrency applicationCurrency = this.applicationCurrencyRepository.findOneWithNotFoundDetection(currency);
final CurrencyData currencyData = applicationCurrency.toData();
final LoanTransaction waiveOfInterest = loan.deriveDefaultInterestWaiverTransaction();
final LoanTransaction waiveOfInterest = deriveDefaultInterestWaiverTransaction(loan);
final LoanTransactionEnumData transactionType = LoanEnumerations.transactionType(LoanTransactionType.WAIVE_INTEREST);
@@ -2235,4 +2235,29 @@ public class LoanReadPlatformServiceImpl implements LoanReadPlatformService, Loa
public boolean existsByLoanId(Long loanId) {
return loanRepositoryWrapper.existsByLoanId(loanId);
}
private LoanTransaction deriveDefaultInterestWaiverTransaction(Loan loan) {
final Money totalInterestOutstanding = loan.getTotalInterestOutstandingOnLoan();
Money possibleInterestToWaive = totalInterestOutstanding.copy();
LocalDate transactionDate = DateUtils.getBusinessLocalDate();
if (totalInterestOutstanding.isGreaterThanZero()) {
// find earliest known instance of overdue interest and default to
// that
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment scheduledRepayment : installments) {
final Money outstandingForPeriod = scheduledRepayment.getInterestOutstanding(loan.getCurrency());
if (scheduledRepayment.isOverdueOn(DateUtils.getBusinessLocalDate()) && scheduledRepayment.isNotFullyPaidOff()
&& outstandingForPeriod.isGreaterThanZero()) {
transactionDate = scheduledRepayment.getDueDate();
possibleInterestToWaive = outstandingForPeriod;
break;
}
}
}
return LoanTransaction.waiver(loan.getOffice(), loan, possibleInterestToWaive, transactionDate, possibleInterestToWaive,
possibleInterestToWaive.zero(), ExternalId.empty());
}
}
@@ -107,6 +107,7 @@ import org.apache.fineract.infrastructure.event.business.service.BusinessEventNo
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.organisation.holiday.domain.Holiday;
import org.apache.fineract.organisation.holiday.domain.HolidayRepositoryWrapper;
import org.apache.fineract.organisation.holiday.service.HolidayUtil;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.organisation.office.domain.Office;
@@ -139,12 +140,14 @@ import org.apache.fineract.portfolio.calendar.domain.CalendarInstanceRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarRepository;
import org.apache.fineract.portfolio.calendar.domain.CalendarType;
import org.apache.fineract.portfolio.calendar.exception.CalendarParameterUpdateNotSupportedException;
import org.apache.fineract.portfolio.calendar.service.CalendarUtils;
import org.apache.fineract.portfolio.client.domain.Client;
import org.apache.fineract.portfolio.client.exception.ClientNotActiveException;
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkDisbursalCommand;
import org.apache.fineract.portfolio.collectionsheet.command.CollectionSheetBulkRepaymentCommand;
import org.apache.fineract.portfolio.collectionsheet.command.SingleDisbursalCommand;
import org.apache.fineract.portfolio.collectionsheet.command.SingleRepaymentCommand;
import org.apache.fineract.portfolio.common.domain.PeriodFrequencyType;
import org.apache.fineract.portfolio.group.domain.Group;
import org.apache.fineract.portfolio.group.exception.GroupNotActiveException;
import org.apache.fineract.portfolio.loanaccount.api.LoanApiConstants;
@@ -2003,10 +2006,10 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
existingReversedTransactionIds);
createAndSaveLoanScheduleArchive(loan, scheduleGeneratorDTO);
} else if (rescheduleBasedOnMeetingDates != null && rescheduleBasedOnMeetingDates) {
loan.updateLoanRepaymentScheduleDates(calendar.getRecurrence(), isHolidayEnabled, holidays, workingDays,
updateLoanRepaymentScheduleDates(loan, calendar.getRecurrence(), isHolidayEnabled, holidays, workingDays,
presentMeetingDate, newMeetingDate, isSkipRepaymentOnFirstMonth, numberOfDays);
} else {
loan.updateLoanRepaymentScheduleDates(calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
updateLoanRepaymentScheduleDates(loan, calendar.getStartDateLocalDate(), calendar.getRecurrence(), isHolidayEnabled,
holidays, workingDays, isSkipRepaymentOnFirstMonth, numberOfDays);
}
@@ -2021,6 +2024,119 @@ public class LoanWritePlatformServiceJpaRepositoryImpl implements LoanWritePlatf
}
}
public void updateLoanRepaymentScheduleDates(final Loan loan, final LocalDate meetingStartDate, final String recuringRule,
final boolean isHolidayEnabled, final List<Holiday> holidays, final WorkingDays workingDays,
final boolean isSkipRepaymentonfirstdayofmonth, final Integer numberofDays) {
// first repayment's from date is same as disbursement date.
LocalDate tmpFromDate = loan.getDisbursementDate();
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
LocalDate newRepaymentDate;
LocalDate latestRepaymentDate = null;
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
// FIXME: AA this won't update repayment dates before current date.
if (DateUtils.isAfter(oldDueDate, meetingStartDate) && DateUtils.isDateInTheFuture(oldDueDate)) {
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recuringRule, meetingStartDate, oldDueDate,
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
final LocalDate maxDateLimitForNewRepayment = getMaxDateLimitForNewRepayment(repaymentPeriodFrequencyType,
loanRepaymentInterval, tmpFromDate);
if (DateUtils.isAfter(newRepaymentDate, maxDateLimitForNewRepayment)) {
newRepaymentDate = CalendarUtils.getNextRepaymentMeetingDate(recuringRule, meetingStartDate, tmpFromDate,
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentonfirstdayofmonth, numberofDays);
}
if (isHolidayEnabled) {
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
}
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
latestRepaymentDate = newRepaymentDate;
}
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
// reset from date to get actual daysInPeriod
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
tmpFromDate = newRepaymentDate;// update with new repayment date
} else {
tmpFromDate = oldDueDate;
}
}
if (latestRepaymentDate != null) {
loan.setExpectedMaturityDate(latestRepaymentDate);
}
}
private LocalDate getMaxDateLimitForNewRepayment(final PeriodFrequencyType periodFrequencyType, final Integer loanRepaymentInterval,
final LocalDate startDate) {
LocalDate dueRepaymentPeriodDate = startDate;
final int repaidEvery = 2 * loanRepaymentInterval;
switch (periodFrequencyType) {
case DAYS -> dueRepaymentPeriodDate = startDate.plusDays(repaidEvery);
case WEEKS -> dueRepaymentPeriodDate = startDate.plusWeeks(repaidEvery);
case MONTHS -> dueRepaymentPeriodDate = startDate.plusMonths(repaidEvery);
case YEARS -> dueRepaymentPeriodDate = startDate.plusYears(repaidEvery);
case INVALID, WHOLE_TERM -> {
}
}
return dueRepaymentPeriodDate.minusDays(1);// get 2n-1 range date from startDate
}
private void updateLoanRepaymentScheduleDates(final Loan loan, final String recurringRule, final boolean isHolidayEnabled,
final List<Holiday> holidays, final WorkingDays workingDays, final LocalDate presentMeetingDate, final LocalDate newMeetingDate,
final boolean isSkipRepaymentOnFirstDayOfMonth, final Integer numberOfDays) {
// first repayment's from date is same as disbursement date.
// meetingStartDate is used as seedDate Capture the seedDate from user and use the seedDate as meetingStart date
LocalDate tmpFromDate = loan.getDisbursementDate();
final PeriodFrequencyType repaymentPeriodFrequencyType = loan.getLoanRepaymentScheduleDetail().getRepaymentPeriodFrequencyType();
final Integer loanRepaymentInterval = loan.getLoanRepaymentScheduleDetail().getRepayEvery();
final String frequency = CalendarUtils.getMeetingFrequencyFromPeriodFrequencyType(repaymentPeriodFrequencyType);
LocalDate newRepaymentDate;
boolean isFirstTime = true;
LocalDate latestRepaymentDate = null;
List<LoanRepaymentScheduleInstallment> installments = loan.getRepaymentScheduleInstallments();
for (final LoanRepaymentScheduleInstallment loanRepaymentScheduleInstallment : installments) {
LocalDate oldDueDate = loanRepaymentScheduleInstallment.getDueDate();
if (!DateUtils.isBefore(oldDueDate, presentMeetingDate)) {
if (isFirstTime) {
isFirstTime = false;
newRepaymentDate = newMeetingDate;
} else {
// tmpFromDate.plusDays(1) is done to make sure
// getNewRepaymentMeetingDate method returns next meeting
// date and not the same as tmpFromDate
newRepaymentDate = CalendarUtils.getNewRepaymentMeetingDate(recurringRule, tmpFromDate, tmpFromDate.plusDays(1),
loanRepaymentInterval, frequency, workingDays, isSkipRepaymentOnFirstDayOfMonth, numberOfDays);
}
if (isHolidayEnabled) {
newRepaymentDate = HolidayUtil.getRepaymentRescheduleDateToIfHoliday(newRepaymentDate, holidays);
}
if (DateUtils.isBefore(latestRepaymentDate, newRepaymentDate)) {
latestRepaymentDate = newRepaymentDate;
}
loanRepaymentScheduleInstallment.updateDueDate(newRepaymentDate);
// reset from date to get actual daysInPeriod
loanRepaymentScheduleInstallment.updateFromDate(tmpFromDate);
tmpFromDate = newRepaymentDate;// update with new repayment date
} else {
tmpFromDate = oldDueDate;
}
}
if (latestRepaymentDate != null) {
loan.setExpectedMaturityDate(latestRepaymentDate);
}
}
private void removeLoanCycle(final Loan loan) {
final List<Loan> loansToUpdate;
if (loan.isGroupLoan()) {
@@ -21,14 +21,18 @@ package org.apache.fineract.portfolio.loanaccount.service;
import java.time.LocalDate;
import java.util.List;
import java.util.Optional;
import java.util.Set;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.organisation.monetary.domain.MonetaryCurrency;
import org.apache.fineract.organisation.monetary.domain.Money;
import org.apache.fineract.portfolio.interestpauses.service.LoanAccountTransfersService;
import org.apache.fineract.portfolio.loanaccount.data.TransactionChangeData;
import org.apache.fineract.portfolio.loanaccount.domain.ChangedTransactionDetail;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanAccountService;
import org.apache.fineract.portfolio.loanaccount.domain.LoanCharge;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleProcessingWrapper;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.transactionprocessor.MoneyHolder;
@@ -83,7 +87,7 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(loan.deriveSumTotalOfChargesDueAtDisbursement());
}
loan.removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loanCharge);
removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(loan, loanCharge);
if (!loanCharge.isDueAtDisbursement() && loanCharge.isPaidOrPartiallyPaid(loan.getCurrency())) {
/*
@@ -100,6 +104,39 @@ public class ReprocessLoanTransactionsServiceImpl implements ReprocessLoanTransa
loan.updateLoanSummaryDerivedFields();
}
private void removeOrModifyTransactionAssociatedWithLoanChargeIfDueAtDisbursement(final Loan loan, final LoanCharge loanCharge) {
if (loanCharge.isDueAtDisbursement()) {
LoanTransaction transactionToRemove = null;
List<LoanTransaction> transactions = loan.getLoanTransactions();
for (final LoanTransaction transaction : transactions) {
if (transaction.isRepaymentAtDisbursement()
&& doesLoanChargePaidByContainLoanCharge(transaction.getLoanChargesPaid(), loanCharge)) {
final MonetaryCurrency currency = loan.getCurrency();
final Money chargeAmount = Money.of(currency, loanCharge.amount());
if (transaction.isGreaterThan(chargeAmount)) {
final Money principalPortion = Money.zero(currency);
final Money interestPortion = Money.zero(currency);
final Money penaltyChargesPortion = Money.zero(currency);
transaction.updateComponentsAndTotal(principalPortion, interestPortion, chargeAmount, penaltyChargesPortion);
} else {
transactionToRemove = transaction;
}
}
}
if (transactionToRemove != null) {
loan.removeLoanTransaction(transactionToRemove);
}
}
}
private boolean doesLoanChargePaidByContainLoanCharge(Set<LoanChargePaidBy> loanChargePaidBys, LoanCharge loanCharge) {
return loanChargePaidBys.stream() //
.anyMatch(loanChargePaidBy -> loanChargePaidBy.getLoanCharge().equals(loanCharge));
}
@Override
public void processLatestTransaction(final LoanTransaction loanTransaction, final Loan loan) {
final ChangedTransactionDetail changedTransactionDetail = loanTransactionProcessingService.processLatestTransaction(
@@ -198,7 +198,7 @@ class LoanChargeWritePlatformServiceImplTest {
when(loan.getLoanCharges()).thenReturn(new HashSet<>());
when(loan.getDisbursementDate()).thenReturn(LocalDate.now(ZoneId.systemDefault()));
when(loan.getRepaymentScheduleInstallments()).thenReturn(new ArrayList<>());
when(loan.calculateAmountPercentageAppliedTo(any(LoanCharge.class))).thenReturn(BigDecimal.TEN);
when(loanChargeService.calculateAmountPercentageAppliedTo(any(Loan.class), any(LoanCharge.class))).thenReturn(BigDecimal.TEN);
when(loan.fetchNumberOfInstallmensAfterExceptions()).thenReturn(5);
when(loan.updateSummaryWithTotalFeeChargesDueAtDisbursement(any(BigDecimal.class))).thenReturn(null);
when(loan.deriveSumTotalOfChargesDueAtDisbursement()).thenReturn(BigDecimal.ZERO);
@@ -219,8 +219,8 @@ class LoanChargeWritePlatformServiceImplTest {
void shouldHandleAccrualBasedOnConfigurationAndDates(boolean isAccrualEnabled, LocalDate businessDate, LocalDate maturityDate, boolean isAccrualExpected) {
when(configurationDomainService.isImmediateChargeAccrualPostMaturityEnabled()).thenReturn(isAccrualEnabled);
when(loan.getMaturityDate()).thenReturn(maturityDate);
when(loan.handleChargeAppliedTransaction(loanCharge, null)).thenReturn(loanTransaction);
when(loan.createChargeAppliedTransaction(loanCharge, null)).thenReturn(loanTransaction);
when(loanChargeService.handleChargeAppliedTransaction(loan, loanCharge, null)).thenReturn(loanTransaction);
when(loanChargeService.createChargeAppliedTransaction(loan, loanCharge, null)).thenReturn(loanTransaction);
if (isAccrualExpected) {
when(loan.isPeriodicAccrualAccountingEnabledOnLoanProduct()).thenReturn(true);