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 .List ;
34+ import java .util .Set ;
3035import java .util .stream .Stream ;
3136import org .apache .fineract .accounting .journalentry .service .JournalEntryWritePlatformService ;
37+ import org .apache .fineract .infrastructure .core .domain .FineractPlatformTenant ;
38+ import org .apache .fineract .infrastructure .core .service .ThreadLocalContextUtil ;
3239import org .apache .fineract .infrastructure .event .business .service .BusinessEventNotifierService ;
40+ import org .apache .fineract .organisation .monetary .domain .MoneyHelper ;
3341import org .apache .fineract .portfolio .loanaccount .domain .Loan ;
42+ import org .apache .fineract .portfolio .loanaccount .domain .LoanChargePaidBy ;
43+ import org .apache .fineract .portfolio .loanaccount .domain .LoanRepaymentScheduleInstallment ;
3444import org .apache .fineract .portfolio .loanaccount .domain .LoanStatus ;
45+ import org .apache .fineract .portfolio .loanaccount .domain .LoanTransaction ;
3546import org .apache .fineract .portfolio .loanaccount .domain .LoanTransactionRepository ;
47+ import org .apache .fineract .portfolio .loanaccount .domain .LoanTransactionToRepaymentScheduleMapping ;
48+ import org .junit .jupiter .api .AfterEach ;
3649import org .junit .jupiter .api .BeforeEach ;
50+ import org .junit .jupiter .api .Test ;
3751import org .junit .jupiter .api .extension .ExtendWith ;
3852import org .junit .jupiter .params .ParameterizedTest ;
3953import org .junit .jupiter .params .provider .Arguments ;
4357import org .mockito .junit .jupiter .MockitoExtension ;
4458import org .mockito .junit .jupiter .MockitoSettings ;
4559import org .mockito .quality .Strictness ;
60+ import org .springframework .test .util .ReflectionTestUtils ;
4661
4762@ ExtendWith (MockitoExtension .class )
4863@ MockitoSettings (strictness = Strictness .LENIENT )
@@ -71,6 +86,15 @@ void setUp() {
7186 when (loan .isClosed ()).thenReturn (false );
7287 when (loan .getStatus ()).thenReturn (loanStatus );
7388 when (loanStatus .isOverpaid ()).thenReturn (false );
89+
90+ ThreadLocalContextUtil .setTenant (new FineractPlatformTenant (1L , "test" , "Test Tenant" , "America/Mexico_City" , null ));
91+ MoneyHelper .initializeTenantRoundingMode ("test" , 6 );
92+ }
93+
94+ @ AfterEach
95+ void tearDown () {
96+ ThreadLocalContextUtil .reset ();
97+ MoneyHelper .clearCache ();
7498 }
7599
76100 @ ParameterizedTest
@@ -95,6 +119,54 @@ void addPeriodicAccruals_ShouldNotProceed_WhenLoanIsClosedOrOverpaid(final boole
95119 verify (loan , never ()).addLoanTransaction (any ());
96120 }
97121
122+ @ Test
123+ void calcInterestTransactionWaivedAmount_ShouldSkipMappingsWithoutTransaction () {
124+ // Given
125+ LocalDate tillDate = LocalDate .now (ZoneId .systemDefault ());
126+ LoanRepaymentScheduleInstallment installment = mock (LoanRepaymentScheduleInstallment .class );
127+ LoanTransactionToRepaymentScheduleMapping nullTransactionMapping = mock (LoanTransactionToRepaymentScheduleMapping .class );
128+ LoanTransactionToRepaymentScheduleMapping interestWaiverMapping = mock (LoanTransactionToRepaymentScheduleMapping .class );
129+ LoanTransaction interestWaiverTransaction = mock (LoanTransaction .class );
130+
131+ when (nullTransactionMapping .getLoanTransaction ()).thenReturn (null );
132+ when (interestWaiverMapping .getLoanTransaction ()).thenReturn (interestWaiverTransaction );
133+ when (interestWaiverMapping .getInterestPortion ()).thenReturn (new BigDecimal ("12.34" ));
134+ when (interestWaiverTransaction .isReversed ()).thenReturn (false );
135+ when (interestWaiverTransaction .isInterestWaiver ()).thenReturn (true );
136+ when (interestWaiverTransaction .getTransactionDate ()).thenReturn (tillDate );
137+ when (installment .getLoanTransactionToRepaymentScheduleMappings ()).thenReturn (Set .of (nullTransactionMapping , interestWaiverMapping ));
138+
139+ // When
140+ BigDecimal result = ReflectionTestUtils .invokeMethod (accrualsProcessingService , "calcInterestTransactionWaivedAmount" , installment ,
141+ tillDate );
142+
143+ // Then
144+ assertThat (result ).isEqualByComparingTo ("12.34" );
145+ }
146+
147+ @ Test
148+ void calcChargeWaivedAmount_ShouldSkipMappingsWithoutTransaction () {
149+ // Given
150+ LocalDate tillDate = LocalDate .now (ZoneId .systemDefault ());
151+ LoanChargePaidBy nullTransactionPaidBy = mock (LoanChargePaidBy .class );
152+ LoanChargePaidBy chargeWaiverPaidBy = mock (LoanChargePaidBy .class );
153+ LoanTransaction chargeWaiverTransaction = mock (LoanTransaction .class );
154+
155+ when (nullTransactionPaidBy .getLoanTransaction ()).thenReturn (null );
156+ when (chargeWaiverPaidBy .getLoanTransaction ()).thenReturn (chargeWaiverTransaction );
157+ when (chargeWaiverPaidBy .getAmount ()).thenReturn (new BigDecimal ("12.34" ));
158+ when (chargeWaiverTransaction .isReversed ()).thenReturn (false );
159+ when (chargeWaiverTransaction .isWaiveCharge ()).thenReturn (true );
160+ when (chargeWaiverTransaction .getTransactionDate ()).thenReturn (tillDate );
161+
162+ // When
163+ BigDecimal result = ReflectionTestUtils .invokeMethod (accrualsProcessingService , "calcChargeWaivedAmount" ,
164+ List .of (nullTransactionPaidBy , chargeWaiverPaidBy ), tillDate );
165+
166+ // Then
167+ assertThat (result ).isEqualByComparingTo ("12.34" );
168+ }
169+
98170 private static Stream <Arguments > loanStatusTestCases () {
99171 return Stream .of (Arguments .of (true , false ), // Loan is closed
100172 Arguments .of (false , true ) // Loan is overpaid
0 commit comments