Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -529,7 +529,7 @@ private BigDecimal calcInterestTransactionWaivedAmount(@NonNull LoanRepaymentSch
Predicate<LoanTransaction> transactionPredicate = t -> !t.isReversed() && t.isInterestWaiver()
&& !DateUtils.isAfter(t.getTransactionDate(), tillDate);
return installment.getLoanTransactionToRepaymentScheduleMappings().stream()
.filter(tm -> transactionPredicate.test(tm.getLoanTransaction()))
.filter(tm -> tm.getLoanTransaction() != null && transactionPredicate.test(tm.getLoanTransaction()))
.map(LoanTransactionToRepaymentScheduleMapping::getInterestPortion).reduce(BigDecimal.ZERO, MathUtil::add);
}

Expand Down Expand Up @@ -639,7 +639,7 @@ private BigDecimal calcChargeWaivedAmount(@NonNull final Collection<LoanChargePa
@NonNull final LocalDate tillDate) {
return loanChargePaidBy.stream().filter(pb -> {
final LoanTransaction t = pb.getLoanTransaction();
return !t.isReversed() && t.isWaiveCharge() && !DateUtils.isAfter(t.getTransactionDate(), tillDate);
return t != null && !t.isReversed() && t.isWaiveCharge() && !DateUtils.isAfter(t.getTransactionDate(), tillDate);
}).map(LoanChargePaidBy::getAmount).reduce(BigDecimal.ZERO, MathUtil::add);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,36 @@
*/
package org.apache.fineract.portfolio.loanaccount.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import static org.mockito.Mockito.when;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.List;
import java.util.Set;
import java.util.stream.Stream;
import org.apache.fineract.accounting.journalentry.service.JournalEntryWritePlatformService;
import org.apache.fineract.infrastructure.core.domain.FineractPlatformTenant;
import org.apache.fineract.infrastructure.core.service.ThreadLocalContextUtil;
import org.apache.fineract.infrastructure.event.business.service.BusinessEventNotifierService;
import org.apache.fineract.organisation.monetary.domain.MoneyHelper;
import org.apache.fineract.portfolio.loanaccount.domain.Loan;
import org.apache.fineract.portfolio.loanaccount.domain.LoanChargePaidBy;
import org.apache.fineract.portfolio.loanaccount.domain.LoanRepaymentScheduleInstallment;
import org.apache.fineract.portfolio.loanaccount.domain.LoanStatus;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransaction;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionRepository;
import org.apache.fineract.portfolio.loanaccount.domain.LoanTransactionToRepaymentScheduleMapping;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
Expand All @@ -43,6 +57,7 @@
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
import org.springframework.test.util.ReflectionTestUtils;

@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
Expand Down Expand Up @@ -71,6 +86,15 @@ void setUp() {
when(loan.isClosed()).thenReturn(false);
when(loan.getStatus()).thenReturn(loanStatus);
when(loanStatus.isOverpaid()).thenReturn(false);

ThreadLocalContextUtil.setTenant(new FineractPlatformTenant(1L, "test", "Test Tenant", "America/Mexico_City", null));
MoneyHelper.initializeTenantRoundingMode("test", 6);
}

@AfterEach
void tearDown() {
ThreadLocalContextUtil.reset();
MoneyHelper.clearCache();
}

@ParameterizedTest
Expand All @@ -95,6 +119,54 @@ void addPeriodicAccruals_ShouldNotProceed_WhenLoanIsClosedOrOverpaid(final boole
verify(loan, never()).addLoanTransaction(any());
}

@Test
void calcInterestTransactionWaivedAmount_ShouldSkipMappingsWithoutTransaction() {
// Given
LocalDate tillDate = LocalDate.now(ZoneId.systemDefault());
LoanRepaymentScheduleInstallment installment = mock(LoanRepaymentScheduleInstallment.class);
LoanTransactionToRepaymentScheduleMapping nullTransactionMapping = mock(LoanTransactionToRepaymentScheduleMapping.class);
LoanTransactionToRepaymentScheduleMapping interestWaiverMapping = mock(LoanTransactionToRepaymentScheduleMapping.class);
LoanTransaction interestWaiverTransaction = mock(LoanTransaction.class);

when(nullTransactionMapping.getLoanTransaction()).thenReturn(null);
when(interestWaiverMapping.getLoanTransaction()).thenReturn(interestWaiverTransaction);
when(interestWaiverMapping.getInterestPortion()).thenReturn(new BigDecimal("12.34"));
when(interestWaiverTransaction.isReversed()).thenReturn(false);
when(interestWaiverTransaction.isInterestWaiver()).thenReturn(true);
when(interestWaiverTransaction.getTransactionDate()).thenReturn(tillDate);
when(installment.getLoanTransactionToRepaymentScheduleMappings()).thenReturn(Set.of(nullTransactionMapping, interestWaiverMapping));

// When
BigDecimal result = ReflectionTestUtils.invokeMethod(accrualsProcessingService, "calcInterestTransactionWaivedAmount", installment,
tillDate);

// Then
assertThat(result).isEqualByComparingTo("12.34");
}

@Test
void calcChargeWaivedAmount_ShouldSkipMappingsWithoutTransaction() {
// Given
LocalDate tillDate = LocalDate.now(ZoneId.systemDefault());
LoanChargePaidBy nullTransactionPaidBy = mock(LoanChargePaidBy.class);
LoanChargePaidBy chargeWaiverPaidBy = mock(LoanChargePaidBy.class);
LoanTransaction chargeWaiverTransaction = mock(LoanTransaction.class);

when(nullTransactionPaidBy.getLoanTransaction()).thenReturn(null);
when(chargeWaiverPaidBy.getLoanTransaction()).thenReturn(chargeWaiverTransaction);
when(chargeWaiverPaidBy.getAmount()).thenReturn(new BigDecimal("12.34"));
when(chargeWaiverTransaction.isReversed()).thenReturn(false);
when(chargeWaiverTransaction.isWaiveCharge()).thenReturn(true);
when(chargeWaiverTransaction.getTransactionDate()).thenReturn(tillDate);

// When
BigDecimal result = ReflectionTestUtils.invokeMethod(accrualsProcessingService, "calcChargeWaivedAmount",
List.of(nullTransactionPaidBy, chargeWaiverPaidBy), tillDate);

// Then
assertThat(result).isEqualByComparingTo("12.34");
}

private static Stream<Arguments> loanStatusTestCases() {
return Stream.of(Arguments.of(true, false), // Loan is closed
Arguments.of(false, true) // Loan is overpaid
Expand Down
Loading