FINERACT-2311: added e2e auto test scenarios for manual journal entries with asset externalization owner

This commit is contained in:
MarianaDmytrivBinariks
2025-07-07 13:59:33 +02:00
committed by Adam Saghy
parent 0c1ca2baba
commit c8b88c3664
4 changed files with 239 additions and 0 deletions
@@ -19,12 +19,14 @@
package org.apache.fineract.test.factory;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.client.models.DisbursementDetail;
import org.apache.fineract.client.models.InterestPauseRequestDto;
import org.apache.fineract.client.models.JournalEntryCommand;
import org.apache.fineract.client.models.PostAddAndDeleteDisbursementDetailRequest;
import org.apache.fineract.client.models.PostCreateRescheduleLoansRequest;
import org.apache.fineract.client.models.PostLoansLoanIdChargesChargeIdRequest;
@@ -34,11 +36,14 @@ import org.apache.fineract.client.models.PostLoansLoanIdTransactionsTransactionI
import org.apache.fineract.client.models.PostLoansRequest;
import org.apache.fineract.client.models.PostUpdateRescheduleLoansRequest;
import org.apache.fineract.client.models.PutLoansLoanIdRequest;
import org.apache.fineract.client.models.SingleDebitOrCreditEntryCommand;
import org.apache.fineract.test.data.InterestCalculationPeriodTime;
import org.apache.fineract.test.data.InterestType;
import org.apache.fineract.test.data.LoanTermFrequencyType;
import org.apache.fineract.test.data.RepaymentFrequencyType;
import org.apache.fineract.test.data.TransactionProcessingStrategyCode;
import org.apache.fineract.test.data.accounttype.AccountTypeResolver;
import org.apache.fineract.test.data.accounttype.DefaultAccountType;
import org.apache.fineract.test.data.loanproduct.DefaultLoanProduct;
import org.apache.fineract.test.data.loanproduct.LoanProductResolver;
import org.apache.fineract.test.helper.Utils;
@@ -87,6 +92,8 @@ public class LoanRequestFactory {
public static final String DATE_WITHDRAWN_STRING = FORMATTER.format(Utils.now().minusMonths(1L));
public static final String DEFAULT_TRANSACTION_DATE = FORMATTER.format(Utils.now().minusMonths(1L));
private final AccountTypeResolver accountTypeResolver;
public PostLoansRequest defaultLoansRequest(Long clientId) {
return new PostLoansRequest()//
.clientId(clientId)//
@@ -312,4 +319,18 @@ public class LoanRequestFactory {
public static PostLoansLoanIdRequest defaultLoanContractTerminationRequest() {
return new PostLoansLoanIdRequest().dateFormat(DATE_FORMAT).locale(DEFAULT_LOCALE).note("Contract Termination");
}
public JournalEntryCommand defaultManualJournalEntryRequest(BigDecimal amount) {
final Long glAccountDebit = accountTypeResolver.resolve(DefaultAccountType.LOANS_RECEIVABLE);
final Long glAccountCredit = accountTypeResolver.resolve(DefaultAccountType.SUSPENSE_CLEARING_ACCOUNT);
return new JournalEntryCommand().amount(BigDecimal.TEN).officeId(1L).currencyCode("USD").locale(DEFAULT_LOCALE)
.dateFormat("uuuu-MM-dd").transactionDate(LocalDate.of(2024, 1, 1))
.addCreditsItem(new SingleDebitOrCreditEntryCommand().glAccountId(glAccountCredit).amount(amount))
.addDebitsItem(new SingleDebitOrCreditEntryCommand().glAccountId(glAccountDebit).amount(amount));
}
public JournalEntryCommand defaultManualJournalEntryRequest(BigDecimal amount, String externalAssetOwner) {
return defaultManualJournalEntryRequest(amount).externalAssetOwner(externalAssetOwner);
}
}
@@ -18,11 +18,14 @@
*/
package org.apache.fineract.test.stepdef.common;
import static org.apache.fineract.test.stepdef.loan.LoanRescheduleStepDef.FORMATTER_EN;
import static org.assertj.core.api.Assertions.assertThat;
import io.cucumber.datatable.DataTable;
import io.cucumber.java.en.Then;
import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
@@ -32,11 +35,14 @@ import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.GetJournalEntriesTransactionIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdResponse;
import org.apache.fineract.client.models.GetLoansLoanIdTransactions;
import org.apache.fineract.client.models.JournalEntryCommand;
import org.apache.fineract.client.models.JournalEntryTransactionItem;
import org.apache.fineract.client.models.PostJournalEntriesResponse;
import org.apache.fineract.client.models.PostLoansResponse;
import org.apache.fineract.client.services.JournalEntriesApi;
import org.apache.fineract.client.services.LoansApi;
import org.apache.fineract.test.data.TransactionType;
import org.apache.fineract.test.factory.LoanRequestFactory;
import org.apache.fineract.test.helper.ErrorHelper;
import org.apache.fineract.test.helper.ErrorMessageHelper;
import org.apache.fineract.test.stepdef.AbstractStepDef;
@@ -55,6 +61,9 @@ public class JournalEntriesStepDef extends AbstractStepDef {
@Autowired
private JournalEntriesApi journalEntriesApi;
@Autowired
private LoanRequestFactory loanRequestFactory;
@Then("Loan Transactions tab has a {string} transaction with date {string} which has the following Journal entries:")
public void journalEntryDataCheck(String transactionType, String transactionDate, DataTable table) throws IOException {
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DATE_FORMAT);
@@ -360,4 +369,131 @@ public class JournalEntriesStepDef extends AbstractStepDef {
assertThat(journalLinesActualList.stream().findFirst().get().size()).isZero();
}
public Response<PostJournalEntriesResponse> addManualJournalEntryWithoutExternalAssetOwner(String amount, String date)
throws IOException {
LocalDate transactionDate = LocalDate.parse(date, FORMATTER_EN);
JournalEntryCommand journalEntriesRequest = loanRequestFactory.defaultManualJournalEntryRequest(new BigDecimal(amount))
.transactionDate(transactionDate);
Response<PostJournalEntriesResponse> journalEntriesResponse = journalEntriesApi.createGLJournalEntry("", journalEntriesRequest)
.execute();
testContext().set(TestContextKey.MANUAL_JOURNAL_ENTRIES_REQUEST, journalEntriesRequest);
return journalEntriesResponse;
}
public Response<PostJournalEntriesResponse> addManualJournalEntryWithExternalAssetOwner(String amount, String date,
String externalAssetOwner) throws IOException {
LocalDate transactionDate = LocalDate.parse(date, FORMATTER_EN);
JournalEntryCommand journalEntriesRequest = loanRequestFactory
.defaultManualJournalEntryRequest(new BigDecimal(amount), externalAssetOwner).transactionDate(transactionDate);
Response<PostJournalEntriesResponse> journalEntriesResponse = journalEntriesApi.createGLJournalEntry("", journalEntriesRequest)
.execute();
testContext().set(TestContextKey.MANUAL_JOURNAL_ENTRIES_REQUEST, journalEntriesRequest);
return journalEntriesResponse;
}
@Then("Admin creates manual Journal entry with {string} amount and {string} date and unique External Asset Owner")
public void createManualJournalEntryWithExternalAssetOwner(String amount, String date) throws IOException {
String ownerExternalIdStored = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID);
Response<PostJournalEntriesResponse> journalEntriesResponse = addManualJournalEntryWithExternalAssetOwner(amount, date,
ownerExternalIdStored);
testContext().set(TestContextKey.MANUAL_JOURNAL_ENTRIES_RESPONSE, journalEntriesResponse);
ErrorHelper.checkSuccessfulApiCall(journalEntriesResponse);
}
@Then("Admin creates manual Journal entry with {string} amount and {string} date and empty External Asset Owner")
public void createManualJournalEntryWithEmptyExternalAssetOwner(String amount, String date) throws IOException {
Response<PostJournalEntriesResponse> journalEntriesResponse = addManualJournalEntryWithExternalAssetOwner(amount, date, "");
testContext().set(TestContextKey.MANUAL_JOURNAL_ENTRIES_RESPONSE, journalEntriesResponse);
ErrorHelper.checkSuccessfulApiCall(journalEntriesResponse);
}
@Then("Admin creates manual Journal entry with {string} amount and {string} date and without External Asset Owner")
public void createManualJournalEntryWithoutExternalAssetOwner(String amount, String date) throws IOException {
Response<PostJournalEntriesResponse> journalEntriesResponse = addManualJournalEntryWithoutExternalAssetOwner(amount, date);
testContext().set(TestContextKey.MANUAL_JOURNAL_ENTRIES_RESPONSE, journalEntriesResponse);
ErrorHelper.checkSuccessfulApiCall(journalEntriesResponse);
}
@Then("Verify manual Journal entry with External Asset Owner {string} and with the following Journal entries:")
public void checkManualJournalEntry(String externalAssetOwnerEnabled, DataTable table) {
Response<PostJournalEntriesResponse> journalEnriesResponse = testContext().get(TestContextKey.MANUAL_JOURNAL_ENTRIES_RESPONSE);
PostJournalEntriesResponse journalEntriesResponseBody = journalEnriesResponse.body();
String transactionId = journalEntriesResponseBody.getTransactionId();
JournalEntryCommand journalEntriesRequest = testContext().get(TestContextKey.MANUAL_JOURNAL_ENTRIES_REQUEST);
Response<GetJournalEntriesTransactionIdResponse> journalEntryDataResponse = null;
try {
journalEntryDataResponse = journalEntriesApi.retrieveAll1(//
null, //
null, //
null, //
null, //
null, //
null, //
null, //
transactionId, //
null, //
null, //
null, //
null, //
null, //
null, //
null, //
null, //
null, //
null, //
true//
).execute();
ErrorHelper.checkSuccessfulApiCall(journalEntryDataResponse);
} catch (IOException e) {
log.error("Exception", e);
}
List<List<String>> data = table.asLists();
for (int i = 1; i < data.size(); i++) {
List<List<List<String>>> possibleActualValuesList = new ArrayList<>();
List<String> expectedValues = data.get(i);
if (Boolean.parseBoolean(externalAssetOwnerEnabled)) {
expectedValues
.add(journalEntriesRequest.getExternalAssetOwner() == null ? null : journalEntriesRequest.getExternalAssetOwner());
}
boolean containsAnyExpected = false;
GetJournalEntriesTransactionIdResponse journalEntryData = journalEntryDataResponse.body();
List<JournalEntryTransactionItem> journalLinesActual = journalEntryData.getPageItems();
List<List<String>> actualValuesList = journalLinesActual.stream().map(t -> {
List<String> actualValues = new ArrayList<>();
actualValues.add(t.getGlAccountType().getValue() == null ? null : t.getGlAccountType().getValue());
actualValues.add(t.getGlAccountCode() == null ? null : t.getGlAccountCode());
actualValues.add(t.getGlAccountName() == null ? null : t.getGlAccountName());
actualValues.add("DEBIT".equals(t.getEntryType().getValue()) ? String.valueOf(t.getAmount()) : null);
actualValues.add("CREDIT".equals(t.getEntryType().getValue()) ? String.valueOf(t.getAmount()) : null);
actualValues.add(String.valueOf(t.getManualEntry()).toLowerCase());
if (Boolean.parseBoolean(externalAssetOwnerEnabled)) {
actualValues.add(t.getExternalAssetOwner() == null ? null : t.getExternalAssetOwner());
}
return actualValues;
}).collect(Collectors.toList());
possibleActualValuesList.add(actualValuesList);
boolean containsExpectedValues = actualValuesList.stream().anyMatch(actualValues -> actualValues.equals(expectedValues));
if (containsExpectedValues) {
containsAnyExpected = true;
}
assertThat(containsAnyExpected)
.as(ErrorMessageHelper.wrongValueInLineInJournalEntries(transactionId, i, possibleActualValuesList, expectedValues))
.isTrue();
}
}
}
@@ -232,4 +232,6 @@ public abstract class TestContextKey {
public static final String DEFAULT_LOAN_PRODUCT_CREATE_RESPONSE_LP2_ADV_PYMNT_INTEREST_DAILY_INTEREST_RECALCULATION_CONTRACT_TERMINATION = "loanProductCreateResponseLP2AdvancedPaymentInterestDailyInterestRecalculationContractTermination";
public static final String LOAN_CONTRACT_TERMINATION_RESPONSE = "loanContractTerminationResponse";
public static final String LOAN_UNDO_CONTRACT_TERMINATION_RESPONSE = "loanUndoContractTerminationResponse";
public static final String MANUAL_JOURNAL_ENTRIES_REQUEST = "manualJournalEntriesRequest";
public static final String MANUAL_JOURNAL_ENTRIES_RESPONSE = "manualJournalEntriesResponse";
}