FINERACT-1926: added e2e tests for asset owner event changes with previous owner

This commit is contained in:
MarianaDmytrivBinariks
2025-08-21 13:50:34 +02:00
committed by Adam Saghy
parent 4786139882
commit 5b638c682b
5 changed files with 381 additions and 7 deletions
@@ -695,6 +695,10 @@ public final class ErrorMessageHelper {
actual, expected);
}
public static String wrongDataInExternalAssetOwnerLoanProductAttribute(String attributeKey, long loanProduct) {
return String.format("No attribute %s for loan product %s is found!", attributeKey, loanProduct);
}
public static String wrongData(String actual, String expected) {
return String.format("Wrong data. Actual value is: %s - But expected value is: %s", actual, expected);
}
@@ -413,6 +413,47 @@ public class EventCheckHelper {
.isEqualTo(transferStatusReasonExpected);
}
public void loanOwnershipTransferBusinessEventWithTypeCheck(Long loanId, ExternalTransferData transferData, String transferType,
String previousAssetOwner) throws IOException {
Response<PageExternalTransferData> response = externalAssetOwnersApi.getTransfers(null, loanId, null, null, null).execute();
List<ExternalTransferData> content = response.body().getContent();
Long transferId = transferData.getTransferId();
String assetOwner = transferData.getOwner() == null ? null : transferData.getOwner().getExternalId();
ExternalTransferData filtered = content.stream().filter(t -> transferId.equals(t.getTransferId())).reduce((first, second) -> second)
.orElseThrow(() -> new IllegalStateException("No element found"));
BigDecimal totalOutstandingBalanceAmountExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalOutstanding());
BigDecimal outstandingPrincipalPortionExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalPrincipalOutstanding());
BigDecimal outstandingFeePortionExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalFeeChargesOutstanding());
BigDecimal outstandingPenaltyPortionExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalPenaltyChargesOutstanding());
BigDecimal outstandingInterestPortionExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalInterestOutstanding());
BigDecimal overPaymentPortionExpected = filtered.getDetails() == null ? null
: zeroConversion(filtered.getDetails().getTotalOverpaid());
eventAssertion.assertEvent(LoanOwnershipTransferEvent.class, loanId).extractingData(LoanOwnershipTransferDataV1::getLoanId)
.isEqualTo(loanId).extractingData(LoanOwnershipTransferDataV1::getAssetOwnerExternalId)
.isEqualTo(filtered.getOwner().getExternalId()).extractingData(LoanOwnershipTransferDataV1::getTransferExternalId)
.isEqualTo(filtered.getTransferExternalId()).extractingData(LoanOwnershipTransferDataV1::getSettlementDate)
.isEqualTo(FORMATTER_EVENTS.format(filtered.getSettlementDate()))
.extractingBigDecimal(LoanOwnershipTransferDataV1::getTotalOutstandingBalanceAmount)
.isEqualTo(totalOutstandingBalanceAmountExpected)
.extractingBigDecimal(LoanOwnershipTransferDataV1::getOutstandingPrincipalPortion)
.isEqualTo(outstandingPrincipalPortionExpected).extractingBigDecimal(LoanOwnershipTransferDataV1::getOutstandingFeePortion)
.isEqualTo(outstandingFeePortionExpected).extractingBigDecimal(LoanOwnershipTransferDataV1::getOutstandingPenaltyPortion)
.isEqualTo(outstandingPenaltyPortionExpected)
.extractingBigDecimal(LoanOwnershipTransferDataV1::getOutstandingInterestPortion)
.isEqualTo(outstandingInterestPortionExpected).extractingBigDecimal(LoanOwnershipTransferDataV1::getOverPaymentPortion)
.isEqualTo(overPaymentPortionExpected).extractingData(LoanOwnershipTransferDataV1::getType).isEqualTo(transferType)
.extractingData(LoanOwnershipTransferDataV1::getAssetOwnerExternalId).isEqualTo(assetOwner)
.extractingData(LoanOwnershipTransferDataV1::getPreviousOwnerExternalId).isEqualTo(previousAssetOwner);
}
public void loanAccountSnapshotBusinessEventCheck(Long loanId, Long transferId) throws IOException {
Response<PageExternalTransferData> response = externalAssetOwnersApi.getTransfers(null, loanId, null, null, null).execute();
List<ExternalTransferData> content = response.body().getContent();
@@ -49,22 +49,33 @@ import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.client.models.CommandProcessingResult;
import org.apache.fineract.client.models.ExternalAssetOwnerRequest;
import org.apache.fineract.client.models.ExternalOwnerJournalEntryData;
import org.apache.fineract.client.models.ExternalOwnerTransferJournalEntryData;
import org.apache.fineract.client.models.ExternalTransferData;
import org.apache.fineract.client.models.ExternalTransferLoanProductAttributesData;
import org.apache.fineract.client.models.GetLoanProductsResponse;
import org.apache.fineract.client.models.JournalEntryData;
import org.apache.fineract.client.models.PageExternalTransferData;
import org.apache.fineract.client.models.PageExternalTransferLoanProductAttributesData;
import org.apache.fineract.client.models.PostExternalAssetOwnerLoanProductAttributeRequest;
import org.apache.fineract.client.models.PostInitiateTransferResponse;
import org.apache.fineract.client.models.PostLoansResponse;
import org.apache.fineract.client.models.PutExternalAssetOwnerLoanProductAttributeRequest;
import org.apache.fineract.client.services.ExternalAssetOwnerLoanProductAttributesApi;
import org.apache.fineract.client.services.ExternalAssetOwnersApi;
import org.apache.fineract.client.services.LoanProductsApi;
import org.apache.fineract.client.services.LoansApi;
import org.apache.fineract.client.util.JSON;
import org.apache.fineract.test.data.AssetExternalizationErrorMessage;
import org.apache.fineract.test.helper.ErrorHelper;
import org.apache.fineract.test.helper.ErrorMessageHelper;
import org.apache.fineract.test.helper.ErrorResponse;
import org.apache.fineract.test.helper.Utils;
import org.apache.fineract.test.messaging.EventAssertion;
import org.apache.fineract.test.messaging.event.EventCheckHelper;
import org.apache.fineract.test.messaging.event.assetexternalization.LoanOwnershipTransferEvent;
import org.apache.fineract.test.stepdef.AbstractStepDef;
import org.apache.fineract.test.support.TestContextKey;
import org.springframework.beans.factory.annotation.Autowired;
@@ -78,6 +89,7 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
public static final String DEFAULT_LOCALE = "en";
public static final String TRANSACTION_TYPE_SALE = "sale";
public static final String TRANSACTION_TYPE_BUYBACK = "buyback";
public static final String TRANSACTION_TYPE_INTERMEDIARY_SALE = "intermediarySale";
public static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern(DATE_FORMAT_ASSET_EXT);
private static final Gson GSON = new JSON().getGson();
@@ -87,6 +99,9 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
@Autowired
private EventCheckHelper eventCheckHelper;
@Autowired
private EventAssertion eventAssertion;
@When("Admin makes asset externalization request by Loan ID with unique ownerExternalId, user-generated transferExternalId and the following data:")
public void createAssetExternalizationRequestByLoanIdUserGeneratedExtId(DataTable table) throws IOException {
// if user created transferExternalId previously, it will use that, otherwise create a new one
@@ -130,7 +145,7 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
response.body().getResourceExternalId());
ErrorHelper.checkSuccessfulApiCall(response);
} else if (transferData.get(0).equals(TRANSACTION_TYPE_SALE)) {
} else if ((transferData.get(0).equals(TRANSACTION_TYPE_SALE) || transferData.get(0).equals(TRANSACTION_TYPE_INTERMEDIARY_SALE))) {
String ownerExternalId;
if (regenerateOwner) {
ownerExternalId = Utils.randomNameGenerator(OWNER_EXTERNAL_ID_PREFIX, 3);
@@ -151,6 +166,13 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
testContext().set(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE,
response.body().getResourceExternalId());
testContext().set(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID, ownerExternalId);
if (transferData.get(0).equals(TRANSACTION_TYPE_INTERMEDIARY_SALE)) {
assertThat(ownerExternalId).isNotNull();
testContext().set(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID, ownerExternalId);
testContext().set(TestContextKey.ASSET_EXTERNALIZATION_INTERMEDIARY_SALE_TRANSFER_EXTERNAL_ID_FROM_RESPONSE,
response.body().getResourceExternalId());
}
ErrorHelper.checkSuccessfulApiCall(response);
} else {
@@ -327,18 +349,50 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
Integer numberOfElementsActual = body.getNumberOfElements();
List<ExternalTransferData> content = body.getContent();
String ownerExternalIdStored = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID);
String transferExternalId;
String ownerExternalIdStored = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID);
String ownerExternalId;
String previousAssetOwner;
String intermediarySaleAssetOwner = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID);
List<List<String>> data = table.asLists();
for (int i = 1; i < data.size(); i++) {
List<String> expectedValues = data.get(i);
String transactionType = expectedValues.get(5);
if (transactionType.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())) {
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else {
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
String status = expectedValues.get(2);
// in case transfer has no previous intermediarySale transfer
if (intermediarySaleAssetOwner == null) {
if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK)
&& status.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())) {
previousAssetOwner = ownerExternalIdStored;
ownerExternalId = ownerExternalIdStored;
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else { // in case of sale or intermediarySale transfer
ownerExternalId = ownerExternalIdStored;
previousAssetOwner = null;
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
}
} else { // in case transfer has previous intermediarySale transfer
if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_SALE)
&& (status.equals(ExternalTransferData.StatusEnum.ACTIVE.getValue())
|| status.equals(ExternalTransferData.StatusEnum.PENDING.getValue()))) {
ownerExternalId = ownerExternalIdStored;
previousAssetOwner = intermediarySaleAssetOwner;
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else if (transactionType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK)
&& (status.equals(ExternalTransferData.StatusEnum.BUYBACK.getValue())
|| status.equals(ExternalTransferData.StatusEnum.BUYBACK_INTERMEDIATE.getValue()))) {
ownerExternalId = ownerExternalIdStored;
previousAssetOwner = ownerExternalIdStored;
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else {
ownerExternalId = intermediarySaleAssetOwner;
previousAssetOwner = null;
transferExternalId = testContext()
.get(TestContextKey.ASSET_EXTERNALIZATION_INTERMEDIARY_SALE_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
}
}
List<List<String>> actualValuesList = content.stream().map(t -> {
@@ -375,13 +429,15 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
: null);
}
actualValues.add(t.getOwner().getExternalId() == null ? null : t.getOwner().getExternalId());
actualValues.add(t.getPreviousOwner() == null ? null : t.getPreviousOwner().getExternalId());
actualValues.add(loanId == null ? null : String.valueOf(t.getLoan().getLoanId()));
actualValues.add(loanExternalId == null ? null : t.getLoan().getExternalId());
actualValues.add(t.getTransferExternalId());
return actualValues;
}).collect(Collectors.toList());
expectedValues.add(ownerExternalIdStored);
expectedValues.add(ownerExternalId);
expectedValues.add(previousAssetOwner);
expectedValues.add(loanId == null ? null : String.valueOf(loanId));
expectedValues.add(loanExternalId);
expectedValues.add(transferExternalId);
@@ -581,6 +637,29 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
return result.getTransferId();
}
private ExternalTransferData getLastTransferByTransferType(Long loanId, String transferType) throws IOException {
String transferExternalId;
if (transferType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK)) {
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else if (transferType.equalsIgnoreCase(TRANSACTION_TYPE_SALE)) {
transferExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else if (transferType.equalsIgnoreCase(TRANSACTION_TYPE_INTERMEDIARY_SALE)) {
transferExternalId = testContext()
.get(TestContextKey.ASSET_EXTERNALIZATION_INTERMEDIARY_SALE_TRANSFER_EXTERNAL_ID_FROM_RESPONSE);
} else {
transferExternalId = null;
}
Response<PageExternalTransferData> transfersResponse = externalAssetOwnersApi.getTransfers(null, loanId, null, null, null)
.execute();
List<ExternalTransferData> content = transfersResponse.body().getContent();
ExternalTransferData result = content.stream().filter(bizEvent -> bizEvent.getTransferExternalId().equals(transferExternalId))
.toList().stream().reduce((first, second) -> second)
.orElseThrow(() -> new IllegalStateException("transfersResponse.body().getContent() is empty"));
return result;
}
@Then("The asset external owner has the following OWNER Journal entries:")
public void checkJournalEntriesOwner(DataTable table) throws IOException {
String ownerExternalId = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID);
@@ -635,6 +714,48 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
eventCheckHelper.loanOwnershipTransferBusinessEventWithStatusCheck(loanId, transferId, transferStatus, transferStatusReason);
}
public String getPreviousAssetOwner(ExternalTransferData transferData, String transferType, boolean isIntermediarySaleTransfer) {
String previousAssetOwner;
String intermediarySaleAssetOwner = testContext().get(TestContextKey.ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID);
String assetOwner = transferData.getOwner() == null ? null : transferData.getOwner().getExternalId();
if ((transferType.equalsIgnoreCase(TRANSACTION_TYPE_SALE) || transferType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK))
&& isIntermediarySaleTransfer) {
previousAssetOwner = intermediarySaleAssetOwner;
} else if (transferType.equalsIgnoreCase(TRANSACTION_TYPE_BUYBACK)) {
previousAssetOwner = assetOwner;
} else {
// in case - transferType is sale(has no intermediarySale before) or intermediarySale
previousAssetOwner = null;
}
return previousAssetOwner;
}
@Then("LoanOwnershipTransferBusinessEvent with transfer type: {string} and transfer asset owner is created")
public void loanOwnershipTransferBusinessEventCheck(String transferType) throws IOException {
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId = loanResponse.body().getLoanId();
ExternalTransferData transferData = getLastTransferByTransferType(loanId, transferType);
String previousAssetOwner = getPreviousAssetOwner(transferData, transferType, false);
eventCheckHelper.loanOwnershipTransferBusinessEventWithTypeCheck(loanId, transferData, transferType, previousAssetOwner);
}
@Then("LoanOwnershipTransferBusinessEvent with transfer type: {string} and transfer asset owner based on intermediarySale is created")
public void loanOwnershipTransferBusinessEventCheckBasedOnIntermediarySale(String transferType) throws IOException {
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
long loanId = loanResponse.body().getLoanId();
ExternalTransferData transferData = getLastTransferByTransferType(loanId, transferType);
String previousAssetOwner = getPreviousAssetOwner(transferData, transferType, true);
eventCheckHelper.loanOwnershipTransferBusinessEventWithTypeCheck(loanId, transferData, transferType, previousAssetOwner);
}
@Then("LoanOwnershipTransferBusinessEvent is not created on {string}")
public void loanOwnershipTransferBusinessEventIsNotRaised(String date) throws IOException {
eventAssertion.assertEventNotRaised(LoanOwnershipTransferEvent.class, em -> FORMATTER.format(em.getBusinessDate()).equals(date));
}
@Then("LoanAccountSnapshotBusinessEvent is created")
public void loanAccountSnapshotBusinessEventCheck() throws IOException {
Response<PostLoansResponse> loanResponse = testContext().get(TestContextKey.LOAN_CREATE_RESPONSE);
@@ -783,6 +904,49 @@ public class AssetExternalizationStepDef extends AbstractStepDef {
ErrorHelper.checkSuccessfulApiCall(response);
}
@Autowired
private LoansApi loansApi;
@Autowired
private LoanProductsApi loanProductsApi;
@Autowired
private ExternalAssetOwnerLoanProductAttributesApi externalAssetOwnerLoanProductAttributesApi;
@When("Admin set external asset owner loan product attribute {string} value {string} for loan product {string}")
public void setAExternalAssetOwnerLoanProductAttribute(String externalAssetOwnerLoanProductAttributeKey,
String externalAssetOwnerLoanProductAttributeValue, String loanProductName) throws IOException {
Response<List<GetLoanProductsResponse>> loanProducts = loanProductsApi.retrieveAllLoanProducts().execute();
long loanProductId = loanProducts.body().stream().filter(loanProduct -> loanProduct.getName().equals(loanProductName)).findFirst()
.orElseThrow(() -> new RuntimeException("No loan product is found!")).getId();
Response<PageExternalTransferLoanProductAttributesData> getExternalAssetOwnerLoanProductAttribute = externalAssetOwnerLoanProductAttributesApi
.getExternalAssetOwnerLoanProductAttributes(loanProductId, externalAssetOwnerLoanProductAttributeKey).execute();
PageExternalTransferLoanProductAttributesData getExternalAssetOwnerLoanProductAttributeBody = getExternalAssetOwnerLoanProductAttribute
.body();
if (getExternalAssetOwnerLoanProductAttributeBody.getTotalFilteredRecords() == 0) {
PostExternalAssetOwnerLoanProductAttributeRequest setLoanProductAttributeRequest = new PostExternalAssetOwnerLoanProductAttributeRequest()
.attributeKey(externalAssetOwnerLoanProductAttributeKey).attributeValue(externalAssetOwnerLoanProductAttributeValue);
Response<CommandProcessingResult> updateLoanProductAttributerEsponse = externalAssetOwnerLoanProductAttributesApi
.postExternalAssetOwnerLoanProductAttribute(loanProductId, setLoanProductAttributeRequest).execute();
ErrorHelper.checkSuccessfulApiCall(updateLoanProductAttributerEsponse);
} else {
List<ExternalTransferLoanProductAttributesData> attributes = getExternalAssetOwnerLoanProductAttributeBody.getPageItems();
assert attributes != null;
long attributeId = attributes.stream()
.filter(attribute -> attribute.getAttributeKey().equals(externalAssetOwnerLoanProductAttributeKey)).findFirst()
.orElseThrow(() -> new RuntimeException(ErrorMessageHelper
.wrongDataInExternalAssetOwnerLoanProductAttribute(externalAssetOwnerLoanProductAttributeKey, loanProductId)))
.getAttributeId();
PutExternalAssetOwnerLoanProductAttributeRequest setLoanProductAttributeRequest = new PutExternalAssetOwnerLoanProductAttributeRequest()
.attributeKey(externalAssetOwnerLoanProductAttributeKey).attributeValue(externalAssetOwnerLoanProductAttributeValue);
Response<CommandProcessingResult> updateLoanProductAttributerEsponse = externalAssetOwnerLoanProductAttributesApi
.updateLoanProductAttribute(loanProductId, attributeId, setLoanProductAttributeRequest).execute();
ErrorHelper.checkSuccessfulApiCall(updateLoanProductAttributerEsponse);
}
}
@When("Admin makes asset externalization request for type {string} by Loan ID with unique ownerExternalId, force generated transferExternalId and without change test owner with following data:")
public void createAssetExternalizationRequestByLoanIdUserGeneratedExtIdForceTransferIdNoTestOwner(String type, DataTable table)
throws IOException {
@@ -233,8 +233,10 @@ public abstract class TestContextKey {
public static final String ASSET_EXTERNALIZATION_TRANSFER_EXTERNAL_ID_FROM_RESPONSE = "assetExternalizationTransferExternalIdFromResponse";
public static final String ASSET_EXTERNALIZATION_SALES_TRANSFER_EXTERNAL_ID_FROM_RESPONSE = "assetExternalizationSalesTransferExternalIdFromResponse";
public static final String ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_EXTERNAL_ID_FROM_RESPONSE = "assetExternalizationBuybackTransferExternalIdFromResponse";
public static final String ASSET_EXTERNALIZATION_INTERMEDIARY_SALE_TRANSFER_EXTERNAL_ID_FROM_RESPONSE = "assetExternalizationIntermediarySaleTransferExternalIdFromResponse";
public static final String ASSET_EXTERNALIZATION_BUYBACK_TRANSFER_PREFIX = "assetExternalizationTransferPrefix";
public static final String ASSET_EXTERNALIZATION_OWNER_EXTERNAL_ID = "assetExternalizationOwnerExternalId";
public static final String ASSET_EXTERNALIZATION_PREVIOUS_OWNER_EXTERNAL_ID = "assetExternalizationPreviousOwnerExternalId";
public static final String TRANSACTION_EVENT = "transactionEvent";
public static final String LOAN_WRITE_OFF_RESPONSE = "loanWriteOffResponse";
public static final String LOAN_DELINQUENCY_ACTION_RESPONSE = "loanDelinquencyActionResponse";
@@ -1309,6 +1309,8 @@ Feature: Asset Externalization
| 2023-05-21 | 1 | PENDING | 2023-05-01 | 2023-05-10 |
| 2023-05-21 | 1 | CANCELLED | 2023-05-01 | 2023-05-10 |
Then LoanOwnershipTransferBusinessEvent is not created on "21 May 2023"
@TestRailId:C2773
Scenario: Verify that active SALE can not be cancelled
When Admin sets the business date to "1 May 2023"
@@ -1332,6 +1334,8 @@ Feature: Asset Externalization
| 2023-05-21 | 1 | ACTIVE | 2023-05-22 | 9999-12-31 | SALE |
When Admin send "cancel" command on "SALE" transaction it will throw an error
Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner is created
@TestRailId:C2774
Scenario: Verify that Asset cannot be cancelled after SALE and BUYBACK is completed
When Admin sets the business date to "1 May 2023"
@@ -1500,6 +1504,7 @@ Feature: Asset Externalization
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING | 2023-05-01 | 2023-05-21 | SALE |
| 2023-05-21 | 1 | ACTIVE | 2023-05-22 | 9999-12-31 | SALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner is created
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| buyback | 2023-05-30 | |
@@ -1518,6 +1523,7 @@ Feature: Asset Externalization
| 2023-05-21 | 1 | PENDING | 2023-05-01 | 2023-05-21 | SALE |
| 2023-05-21 | 1 | ACTIVE | 2023-05-22 | 2023-05-25 | SALE |
| 2023-05-30 | 1 | BUYBACK | 2023-05-22 | 2023-05-25 | BUYBACK |
Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner is created
@TestRailId:C2788
Scenario: Verify that when a loan with PENDING BUYBACK is overpaid BUYBACK transaction can be done successfully
@@ -1856,3 +1862,160 @@ Feature: Asset Externalization
| ASSET | 112601 | Loans Receivable | 250.05 | | true |
| LIABILITY | 145023 | Suspense/Clearing account | | 250.05 | true |
Given Global configuration "asset-externalization-of-non-active-loans" is enabled
@TestRailId:C3991
Scenario: Verify asset externalization previous owner for intermediarySale transfer with following SALES request - UC1
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE"
When Admin sets the business date to "1 May 2023"
When Admin creates a client with random data
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023"
When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount
Then Loan status will be "ACTIVE"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| intermediarySale | 2023-05-21 | 1 |
Then Asset externalization response has the correct Loan ID, transferExternalId
Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE |
When Admin sets the business date to "22 May 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created
When Admin sets the business date to "14 June 2023"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| sale | 2023-06-14 | 1 |
Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 9999-12-31 | SALE |
When Admin sets the business date to "15 June 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 4 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE |
| 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE"
@TestRailId:C3992
Scenario: Verify asset externalization previous owner for intermediarySale transfer with following SALES and BUYBACK requests - UC2
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE"
When Admin sets the business date to "1 May 2023"
When Admin creates a client with random data
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023"
When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount
Then Loan status will be "ACTIVE"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| intermediarySale | 2023-05-21 | 1 |
Then Asset externalization response has the correct Loan ID, transferExternalId
Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE |
When Admin sets the business date to "22 May 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created
When Admin sets the business date to "14 June 2023"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| sale | 2023-06-14 | 1 |
Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 9999-12-31 | SALE |
When Admin sets the business date to "15 June 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 4 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE |
| 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "SALE" and transfer asset owner based on intermediarySale is created
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| buyback | 2023-06-16 | |
Then Fetching Asset externalization details by loan id gives numberOfElements: 5 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE |
| 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 9999-12-31 | SALE |
| 2023-06-16 | 1 | BUYBACK | 2023-06-15 | 9999-12-31 | BUYBACK |
When Admin sets the business date to "17 June 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 5 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | PENDING | 2023-06-14 | 2023-06-14 | SALE |
| 2023-06-14 | 1 | ACTIVE | 2023-06-15 | 2023-06-16 | SALE |
| 2023-06-16 | 1 | BUYBACK | 2023-06-15 | 2023-06-16 | BUYBACK |
Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner is created
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE"
@TestRailId:C3993
Scenario: Verify asset externalization previous owner for intermediarySale transfer with following BUYBACK requests - UC3
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DELAYED_SETTLEMENT" for loan product "LP1_DUE_DATE"
When Admin sets the business date to "1 May 2023"
When Admin creates a client with random data
When Admin creates a fully customized loan with the following data:
| LoanProduct | submitted on date | with Principal | ANNUAL interest rate % | interest type | interest calculation period | amortization type | loanTermFrequency | loanTermFrequencyType | repaymentEvery | repaymentFrequencyType | numberOfRepayments | graceOnPrincipalPayment | graceOnInterestPayment | interest free period | Payment strategy |
| LP1_DUE_DATE | 01 May 2023 | 1000 | 0 | DECLINING_BALANCE | SAME_AS_REPAYMENT_PERIOD | EQUAL_INSTALLMENTS | 1 | MONTHS | 1 | MONTHS | 1 | 0 | 0 | 0 | PENALTIES_FEES_INTEREST_PRINCIPAL_ORDER |
And Admin successfully approves the loan on "1 May 2023" with "1000" amount and expected disbursement date on "1 May 2023"
When Admin successfully disburse the loan on "1 May 2023" with "1000" EUR transaction amount
Then Loan status will be "ACTIVE"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| intermediarySale | 2023-05-21 | 1 |
Then Asset externalization response has the correct Loan ID, transferExternalId
Then Fetching Asset externalization details by loan id gives numberOfElements: 1 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 9999-12-31 | INTERMEDIARYSALE |
When Admin sets the business date to "22 May 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 2 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
Then LoanOwnershipTransferBusinessEvent with transfer type: "INTERMEDIARYSALE" and transfer asset owner is created
When Admin sets the business date to "14 June 2023"
When Admin makes asset externalization request by Loan ID with unique ownerExternalId, system-generated transferExternalId and the following data:
| Transaction type | settlementDate | purchasePriceRatio |
| buyback | 2023-06-14 | |
Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 9999-12-31 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | BUYBACK_INTERMEDIATE | 2023-06-14 | 9999-12-31 | BUYBACK |
When Admin sets the business date to "15 June 2023"
When Admin runs inline COB job for Loan
Then Fetching Asset externalization details by loan id gives numberOfElements: 3 with correct ownerExternalId and the following data:
| settlementDate | purchasePriceRatio | status | effectiveFrom | effectiveTo | Transaction type |
| 2023-05-21 | 1 | PENDING_INTERMEDIATE | 2023-05-01 | 2023-05-21 | INTERMEDIARYSALE |
| 2023-05-21 | 1 | ACTIVE_INTERMEDIATE | 2023-05-22 | 2023-06-14 | INTERMEDIARYSALE |
| 2023-06-14 | 1 | BUYBACK_INTERMEDIATE | 2023-06-14 | 2023-06-14 | BUYBACK |
Then LoanOwnershipTransferBusinessEvent with transfer type: "BUYBACK" and transfer asset owner based on intermediarySale is created
When Admin set external asset owner loan product attribute "SETTLEMENT_MODEL" value "DEFAULT_SETTLEMENT" for loan product "LP1_DUE_DATE"