1818 */
1919package org .apache .fineract .test .stepdef .loan ;
2020
21+ import static org .apache .fineract .client .feign .util .FeignCalls .fail ;
2122import static org .apache .fineract .client .feign .util .FeignCalls .ok ;
2223import static org .assertj .core .api .Assertions .assertThat ;
2324
2425import io .cucumber .datatable .DataTable ;
2526import io .cucumber .java .en .Then ;
27+ import io .cucumber .java .en .When ;
2628import java .math .BigDecimal ;
2729import java .time .LocalDate ;
2830import java .util .List ;
2931import lombok .RequiredArgsConstructor ;
3032import lombok .extern .slf4j .Slf4j ;
3133import org .apache .fineract .client .feign .FineractFeignClient ;
34+ import org .apache .fineract .client .feign .util .CallFailedRuntimeException ;
35+ import org .apache .fineract .client .models .PostWorkingCapitalLoansDelinquencyActionRequest ;
36+ import org .apache .fineract .client .models .PostWorkingCapitalLoansDelinquencyActionResponse ;
3237import org .apache .fineract .client .models .PostWorkingCapitalLoansResponse ;
38+ import org .apache .fineract .client .models .WorkingCapitalLoanDelinquencyActionData ;
3339import org .apache .fineract .client .models .WorkingCapitalLoanDelinquencyRangeScheduleData ;
40+ import org .apache .fineract .test .factory .WorkingCapitalLoanRequestFactory ;
3441import org .apache .fineract .test .stepdef .AbstractStepDef ;
3542import org .apache .fineract .test .support .TestContextKey ;
3643
3946public class WorkingCapitalDelinquencyStepDef extends AbstractStepDef {
4047
4148 private final FineractFeignClient fineractClient ;
49+ private final WorkingCapitalLoanRequestFactory workingCapitalLoanRequestFactory ;
50+
51+ @ When ("Admin initiate a Working Capital loan delinquency pause with startDate {string} and endDate {string}" )
52+ public void initiateDelinquencyPause (String startDate , String endDate ) {
53+ Long loanId = extractLoanId ();
54+ PostWorkingCapitalLoansDelinquencyActionRequest request = buildDelinquencyActionRequest ("pause" , startDate , endDate );
55+ PostWorkingCapitalLoansDelinquencyActionResponse response = createDelinquencyActionById (loanId , request );
56+
57+ log .debug ("Delinquency pause initiated for loan {} with startDate: {}, endDate: {}, response: {}" , loanId , startDate , endDate ,
58+ response );
59+ }
60+
61+ @ When ("Admin initiate a Working Capital loan delinquency pause by external ID with startDate {string} and endDate {string}" )
62+ public void initiateDelinquencyPauseByExternalId (String startDate , String endDate ) {
63+ String loanExternalId = extractLoanExternalId ();
64+ PostWorkingCapitalLoansDelinquencyActionRequest request = buildDelinquencyActionRequest ("pause" , startDate , endDate );
65+ PostWorkingCapitalLoansDelinquencyActionResponse response = createDelinquencyActionByExternalId (loanExternalId , request );
66+
67+ log .debug ("Delinquency pause initiated for loan externalId {} with startDate: {}, endDate: {}, response: {}" , loanExternalId ,
68+ startDate , endDate , response );
69+ }
70+
71+ @ Then ("Initiating a Working Capital loan delinquency pause with startDate {string} and endDate {string} results an error" )
72+ public void initiateDelinquencyPauseResultsAnError (String startDate , String endDate ) {
73+ initiateDelinquencyPauseResultsAnErrorWithDetails (startDate , endDate , null );
74+ }
75+
76+ @ Then ("Initiating a Working Capital loan delinquency pause with startDate {string} and endDate {string} results an error with the following data:" )
77+ public void initiateDelinquencyPauseResultsAnErrorWithDetails (String startDate , String endDate , DataTable table ) {
78+ Long loanId = extractLoanId ();
79+
80+ PostWorkingCapitalLoansDelinquencyActionRequest request = workingCapitalLoanRequestFactory
81+ .defaultWorkingCapitalLoansDelinquencyActionRequest ("pause" ).startDate (startDate ).endDate (endDate );
82+
83+ CallFailedRuntimeException exception = fail (
84+ () -> fineractClient .workingCapitalLoanDelinquencyActions ().createDelinquencyAction (loanId , request ));
85+
86+ if (table != null ) {
87+ verifyDelinquencyPauseErrorWithTable (exception , table );
88+ } else {
89+ // Default error for backward compatibility
90+ verifyDelinquencyPauseError (exception , 400 ,
91+ "Pause start date cannot fall within or before an already evaluated delinquency range period" );
92+ }
93+
94+ log .info ("Verified delinquency pause initiation failed with expected error for loan {}" , loanId );
95+ }
96+
97+ @ Then ("Working Capital loan delinquency action has the following data:" )
98+ public void verifyDelinquencyAction (DataTable dataTable ) {
99+ Long loanId = extractLoanId ();
100+ List <WorkingCapitalLoanDelinquencyActionData > actualActions = retrieveDelinquencyActions (loanId );
101+ verifyDelinquencyActionsWithTable (actualActions , dataTable );
102+ }
103+
104+ @ Then ("Working Capital loan delinquency action by external ID has the following data:" )
105+ public void verifyDelinquencyActionByExternalId (DataTable dataTable ) {
106+ String loanExternalId = extractLoanExternalId ();
107+ List <WorkingCapitalLoanDelinquencyActionData > actualActions = retrieveDelinquencyActionsByExternalId (loanExternalId );
108+ verifyDelinquencyActionsWithTable (actualActions , dataTable );
109+ }
110+
111+ private void verifyDelinquencyActionsWithTable (List <WorkingCapitalLoanDelinquencyActionData > actualActions , DataTable dataTable ) {
112+ assertThat (actualActions ).as ("Delinquency actions should not be empty" ).isNotEmpty ();
113+
114+ List <List <String >> rows = dataTable .asLists ();
115+ List <String > headers = rows .get (0 );
116+ List <List <String >> expectedData = rows .subList (1 , rows .size ());
117+
118+ verifyDelinquencyActionsSize (actualActions , expectedData .size ());
119+ verifyAllDelinquencyActionFields (actualActions , headers , expectedData );
120+
121+ log .info ("Successfully verified {} delinquency action(s)" , actualActions .size ());
122+ }
123+
124+ private void verifyDelinquencyActionField (WorkingCapitalLoanDelinquencyActionData actual , String fieldName , String expectedValue ,
125+ int rowNumber ) {
126+ switch (fieldName ) {
127+ case "action" -> assertThat (actual .getAction ().name ()).as ("Action for row %d" , rowNumber ).isEqualTo (expectedValue );
128+ case "startDate" ->
129+ assertThat (actual .getStartDate ()).as ("Start date for row %d" , rowNumber ).isEqualTo (LocalDate .parse (expectedValue ));
130+ case "endDate" ->
131+ assertThat (actual .getEndDate ()).as ("End date for row %d" , rowNumber ).isEqualTo (LocalDate .parse (expectedValue ));
132+ default -> throw new IllegalArgumentException ("Unknown field name: " + fieldName );
133+ }
134+ }
42135
43136 @ Then ("Working Capital loan delinquency range schedule has no data on a not yet disbursed loan" )
44137 public void verifyRangeScheduleIsEmpty () {
@@ -76,6 +169,44 @@ private Long extractLoanId() {
76169 return loanResponse .getLoanId ();
77170 }
78171
172+ private String extractLoanExternalId () {
173+ Long loanId = extractLoanId ();
174+ return retrieveLoanExternalId (loanId );
175+ }
176+
177+ private String retrieveLoanExternalId (Long loanId ) {
178+ return ok (() -> fineractClient .workingCapitalLoans ().retrieveWorkingCapitalLoanById (loanId )).getExternalId ();
179+ }
180+
181+ private PostWorkingCapitalLoansDelinquencyActionRequest buildDelinquencyActionRequest (String action , String startDate , String endDate ) {
182+ return workingCapitalLoanRequestFactory .defaultWorkingCapitalLoansDelinquencyActionRequest (action ).startDate (startDate )
183+ .endDate (endDate );
184+ }
185+
186+ private PostWorkingCapitalLoansDelinquencyActionResponse createDelinquencyActionById (Long loanId ,
187+ PostWorkingCapitalLoansDelinquencyActionRequest request ) {
188+ return ok (() -> fineractClient .workingCapitalLoanDelinquencyActions ().createDelinquencyAction (loanId , request ));
189+ }
190+
191+ private PostWorkingCapitalLoansDelinquencyActionResponse createDelinquencyActionByExternalId (String loanExternalId ,
192+ PostWorkingCapitalLoansDelinquencyActionRequest request ) {
193+ return ok (() -> fineractClient .workingCapitalLoanDelinquencyActions ().createDelinquencyActionByExternalId (loanExternalId , request ));
194+ }
195+
196+ private List <WorkingCapitalLoanDelinquencyActionData > retrieveDelinquencyActions (Long loanId ) {
197+ List <WorkingCapitalLoanDelinquencyActionData > actions = ok (
198+ () -> fineractClient .workingCapitalLoanDelinquencyActions ().retrieveDelinquencyActions (loanId ));
199+ log .debug ("Delinquency actions for loan {}: {}" , loanId , actions );
200+ return actions ;
201+ }
202+
203+ private List <WorkingCapitalLoanDelinquencyActionData > retrieveDelinquencyActionsByExternalId (String loanExternalId ) {
204+ List <WorkingCapitalLoanDelinquencyActionData > actions = ok (
205+ () -> fineractClient .workingCapitalLoanDelinquencyActions ().retrieveDelinquencyActionsByExternalId (loanExternalId ));
206+ log .debug ("Delinquency actions for loan externalId {}: {}" , loanExternalId , actions );
207+ return actions ;
208+ }
209+
79210 private List <WorkingCapitalLoanDelinquencyRangeScheduleData > retrieveRangeSchedule (Long loanId ) {
80211 List <WorkingCapitalLoanDelinquencyRangeScheduleData > rangeSchedule = ok (
81212 () -> fineractClient .workingCapitalLoanDelinquencyRangeSchedule ().retrieveDelinquencyRangeSchedule (loanId ));
@@ -87,6 +218,24 @@ private void verifyRangeScheduleSize(List<WorkingCapitalLoanDelinquencyRangeSche
87218 assertThat (actualRangeSchedule ).as ("Range schedule size should match expected data" ).hasSize (expectedSize );
88219 }
89220
221+ private void verifyDelinquencyActionsSize (List <WorkingCapitalLoanDelinquencyActionData > actualActions , int expectedSize ) {
222+ assertThat (actualActions ).as ("Delinquency actions size should match expected data" ).hasSize (expectedSize );
223+ }
224+
225+ private void verifyAllDelinquencyActionFields (List <WorkingCapitalLoanDelinquencyActionData > actualActions , List <String > headers ,
226+ List <List <String >> expectedData ) {
227+ for (int i = 0 ; i < expectedData .size (); i ++) {
228+ List <String > expectedRow = expectedData .get (i );
229+ WorkingCapitalLoanDelinquencyActionData actualAction = actualActions .get (i );
230+
231+ for (int j = 0 ; j < headers .size (); j ++) {
232+ String header = headers .get (j );
233+ String expectedValue = expectedRow .get (j );
234+ verifyDelinquencyActionField (actualAction , header , expectedValue , i + 1 );
235+ }
236+ }
237+ }
238+
90239 private void verifyAllRangeScheduleFields (List <WorkingCapitalLoanDelinquencyRangeScheduleData > actualRangeSchedule ,
91240 List <String > headers , List <List <String >> expectedData ) {
92241 for (int i = 0 ; i < expectedData .size (); i ++) {
@@ -148,4 +297,23 @@ private void verifyNullableLong(Long actualValue, String expectedValue, String f
148297 }
149298 }
150299
300+ private void verifyDelinquencyPauseError (CallFailedRuntimeException exception , int expectedHttpCode , String expectedErrorMessage ) {
301+ log .info ("Checking for Http code: {} and error message: \" {}\" " , expectedHttpCode , expectedErrorMessage );
302+
303+ assertThat (exception .getStatus ()).as ("HTTP status code should be " + expectedHttpCode ).isEqualTo (expectedHttpCode );
304+ assertThat (exception .getMessage ()).as ("Should contain error message" ).contains (expectedErrorMessage );
305+ }
306+
307+ private void verifyDelinquencyPauseErrorWithTable (CallFailedRuntimeException exception , DataTable table ) {
308+ List <List <String >> data = table .asLists ();
309+ String expectedHttpCode = data .get (1 ).get (0 );
310+ String expectedErrorMessage = data .get (1 ).get (1 );
311+
312+ log .info ("Checking for Http code: {} and error message: \" {}\" " , expectedHttpCode , expectedErrorMessage );
313+
314+ assertThat (exception .getStatus ()).as ("HTTP status code should be " + expectedHttpCode )
315+ .isEqualTo (Integer .parseInt (expectedHttpCode ));
316+ assertThat (exception .getMessage ()).as ("Should contain error message" ).contains (expectedErrorMessage );
317+ }
318+
151319}
0 commit comments