1818 */
1919package org .apache .fineract .portfolio .loanaccount .service ;
2020
21+ import static org .assertj .core .api .Assertions .assertThat ;
2122import static org .mockito .ArgumentMatchers .any ;
23+ import static org .mockito .Mockito .mock ;
2224import static org .mockito .Mockito .never ;
2325import static org .mockito .Mockito .times ;
2426import static org .mockito .Mockito .verify ;
2527import static org .mockito .Mockito .verifyNoInteractions ;
2628import static org .mockito .Mockito .when ;
2729
30+ import java .math .BigDecimal ;
2831import java .time .LocalDate ;
2932import java .time .ZoneId ;
33+ import java .util .Set ;
3034import java .util .stream .Stream ;
3135import org .apache .fineract .accounting .journalentry .service .JournalEntryWritePlatformService ;
36+ import org .apache .fineract .infrastructure .core .domain .FineractPlatformTenant ;
37+ import org .apache .fineract .infrastructure .core .service .ThreadLocalContextUtil ;
3238import org .apache .fineract .infrastructure .event .business .service .BusinessEventNotifierService ;
39+ import org .apache .fineract .organisation .monetary .domain .MoneyHelper ;
3340import org .apache .fineract .portfolio .loanaccount .domain .Loan ;
41+ import org .apache .fineract .portfolio .loanaccount .domain .LoanRepaymentScheduleInstallment ;
3442import org .apache .fineract .portfolio .loanaccount .domain .LoanStatus ;
43+ import org .apache .fineract .portfolio .loanaccount .domain .LoanTransaction ;
3544import org .apache .fineract .portfolio .loanaccount .domain .LoanTransactionRepository ;
45+ import org .apache .fineract .portfolio .loanaccount .domain .LoanTransactionToRepaymentScheduleMapping ;
46+ import org .junit .jupiter .api .AfterEach ;
3647import org .junit .jupiter .api .BeforeEach ;
48+ import org .junit .jupiter .api .Test ;
3749import org .junit .jupiter .api .extension .ExtendWith ;
3850import org .junit .jupiter .params .ParameterizedTest ;
3951import org .junit .jupiter .params .provider .Arguments ;
4355import org .mockito .junit .jupiter .MockitoExtension ;
4456import org .mockito .junit .jupiter .MockitoSettings ;
4557import org .mockito .quality .Strictness ;
58+ import org .springframework .test .util .ReflectionTestUtils ;
4659
4760@ ExtendWith (MockitoExtension .class )
4861@ MockitoSettings (strictness = Strictness .LENIENT )
@@ -71,6 +84,15 @@ void setUp() {
7184 when (loan .isClosed ()).thenReturn (false );
7285 when (loan .getStatus ()).thenReturn (loanStatus );
7386 when (loanStatus .isOverpaid ()).thenReturn (false );
87+
88+ ThreadLocalContextUtil .setTenant (new FineractPlatformTenant (1L , "test" , "Test Tenant" , "America/Mexico_City" , null ));
89+ MoneyHelper .initializeTenantRoundingMode ("test" , 6 );
90+ }
91+
92+ @ AfterEach
93+ void tearDown () {
94+ ThreadLocalContextUtil .reset ();
95+ MoneyHelper .clearCache ();
7496 }
7597
7698 @ ParameterizedTest
@@ -95,6 +117,31 @@ void addPeriodicAccruals_ShouldNotProceed_WhenLoanIsClosedOrOverpaid(final boole
95117 verify (loan , never ()).addLoanTransaction (any ());
96118 }
97119
120+ @ Test
121+ void calcInterestTransactionWaivedAmount_ShouldSkipMappingsWithoutTransaction () {
122+ // Given
123+ LocalDate tillDate = LocalDate .now (ZoneId .systemDefault ());
124+ LoanRepaymentScheduleInstallment installment = mock (LoanRepaymentScheduleInstallment .class );
125+ LoanTransactionToRepaymentScheduleMapping nullTransactionMapping = mock (LoanTransactionToRepaymentScheduleMapping .class );
126+ LoanTransactionToRepaymentScheduleMapping interestWaiverMapping = mock (LoanTransactionToRepaymentScheduleMapping .class );
127+ LoanTransaction interestWaiverTransaction = mock (LoanTransaction .class );
128+
129+ when (nullTransactionMapping .getLoanTransaction ()).thenReturn (null );
130+ when (interestWaiverMapping .getLoanTransaction ()).thenReturn (interestWaiverTransaction );
131+ when (interestWaiverMapping .getInterestPortion ()).thenReturn (new BigDecimal ("12.34" ));
132+ when (interestWaiverTransaction .isReversed ()).thenReturn (false );
133+ when (interestWaiverTransaction .isInterestWaiver ()).thenReturn (true );
134+ when (interestWaiverTransaction .getTransactionDate ()).thenReturn (tillDate );
135+ when (installment .getLoanTransactionToRepaymentScheduleMappings ()).thenReturn (Set .of (nullTransactionMapping , interestWaiverMapping ));
136+
137+ // When
138+ BigDecimal result = ReflectionTestUtils .invokeMethod (accrualsProcessingService , "calcInterestTransactionWaivedAmount" , installment ,
139+ tillDate );
140+
141+ // Then
142+ assertThat (result ).isEqualByComparingTo ("12.34" );
143+ }
144+
98145 private static Stream <Arguments > loanStatusTestCases () {
99146 return Stream .of (Arguments .of (true , false ), // Loan is closed
100147 Arguments .of (false , true ) // Loan is overpaid
0 commit comments