blob: 0cce0b4b44064ba76bb45d9a9eef2d52263c8fac [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.fineract.integrationtests.interoperation;
import static org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper.ACCOUNT_TYPE_INDIVIDUAL;
import static org.apache.fineract.integrationtests.interoperation.InteropHelper.PARAM_ACCOUNT_BALANCE;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.internal.common.path.ObjectConverter;
import io.restassured.path.json.JsonPath;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import org.apache.fineract.infrastructure.core.service.MathUtil;
import org.apache.fineract.integrationtests.common.ClientHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.apache.fineract.integrationtests.common.accounting.Account;
import org.apache.fineract.integrationtests.common.accounting.AccountHelper;
import org.apache.fineract.integrationtests.common.charges.ChargesHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsAccountHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsProductHelper;
import org.apache.fineract.integrationtests.common.savings.SavingsStatusChecker;
import org.apache.fineract.interoperation.domain.InteropActionState;
import org.apache.fineract.interoperation.domain.InteropIdentifierType;
import org.apache.fineract.interoperation.domain.InteropTransactionRole;
import org.apache.fineract.interoperation.util.InteropUtil;
import org.apache.fineract.portfolio.charge.domain.ChargeTimeType;
import org.apache.fineract.portfolio.savings.SavingsApiConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class InteropTest {
private static final Logger LOG = LoggerFactory.getLogger(InteropTest.class);
private static final String MIN_INTEREST_CALCULATON_BALANCE = null;
private static final String MIN_REQUIRED_BALANCE = null;
private static final String MIN_OPENING_BALANCE = "100000.0";
private static final boolean ENFORCE_MIN_REQUIRED_BALANCE = false;
private static final MathContext MATHCONTEXT = new MathContext(12, RoundingMode.HALF_EVEN);
private RequestSpecification requestSpec;
private ResponseSpecification responseSpec;
private ResponseSpecification responseClientErrorSpec;
private ResponseSpecification responseNotFoundErrorSpec;
private ResponseSpecification responseForbiddenErrorSpec;
private AccountHelper accountHelper;
private SavingsAccountHelper savingsAccountHelper;
private InteropHelper interopHelper;
private Integer clientId;
private Integer savingsProductId;
private Integer savingsId;
private Integer chargeId;
private String requestCode;
private String quoteCode;
private String transferCode;
@BeforeEach
public void setup() {
Utils.initializeRESTAssured();
requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
responseClientErrorSpec = new ResponseSpecBuilder().expectStatusCode(400).build();
responseForbiddenErrorSpec = new ResponseSpecBuilder().expectStatusCode(403).build();
responseNotFoundErrorSpec = new ResponseSpecBuilder().expectStatusCode(404).build();
String savingsExternalId = UUID.randomUUID().toString();
String transactionCode = UUID.randomUUID().toString();
accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
savingsAccountHelper = new SavingsAccountHelper(requestSpec, responseSpec);
interopHelper = new InteropHelper(requestSpec, responseSpec, savingsExternalId, transactionCode);
}
@Test
public void testValidateAction() {
interopHelper.setResponseSpec(responseClientErrorSpec);
interopHelper.postTransferMissingAction(UUID.randomUUID().toString(), InteropTransactionRole.PAYER);
interopHelper.postTransfer(UUID.randomUUID().toString(), null, InteropTransactionRole.PAYER);
interopHelper.setResponseSpec(responseSpec);
}
@Test
public void testInteroperation() {
createClient();
createSavingsProduct();
createCharge();
openSavingsAccount();
testParties();
testRequests();
testQuotes();
testTransfers();
}
private void createClient() {
clientId = ClientHelper.createClient(requestSpec, responseSpec);
Assertions.assertNotNull(clientId);
}
private void createSavingsProduct() {
LOG.debug("------------------------------ Create Interoperable Saving Product ---------------------------------------");
Account[] accounts = { accountHelper.createAssetAccount(), accountHelper.createIncomeAccount(),
accountHelper.createExpenseAccount(), accountHelper.createLiabilityAccount() };
SavingsProductHelper savingsProductHelper = new SavingsProductHelper();
final String savingsProductJSON = savingsProductHelper.withCurrencyCode(interopHelper.getCurrency())
.withNominalAnnualInterestRate(BigDecimal.ZERO).withInterestCompoundingPeriodTypeAsDaily()
.withInterestPostingPeriodTypeAsMonthly().withInterestCalculationPeriodTypeAsDailyBalance()
.withMinBalanceForInterestCalculation(MIN_INTEREST_CALCULATON_BALANCE).withMinRequiredBalance(MIN_REQUIRED_BALANCE)
.withEnforceMinRequiredBalance(Boolean.toString(ENFORCE_MIN_REQUIRED_BALANCE))
.withMinimumOpenningBalance(MIN_OPENING_BALANCE).withAccountingRuleAsCashBased(accounts).build();
savingsProductId = SavingsProductHelper.createSavingsProduct(savingsProductJSON, requestSpec, responseSpec);
Assertions.assertNotNull(savingsProductId);
LOG.debug("Sucessfully created Interoperable Saving Product (id: {})", savingsProductId);
}
private void createCharge() {
chargeId = ChargesHelper.createCharges(requestSpec, responseSpec, ChargesHelper.getSavingsJSON(interopHelper.getFee().toString(),
interopHelper.getCurrency(), ChargeTimeType.WITHDRAWAL_FEE));
Assertions.assertNotNull(chargeId);
}
private void openSavingsAccount() {
LOG.debug("------------------------------ Create Interoperable Saving Account ---------------------------------------");
savingsId = savingsAccountHelper.applyForSavingsApplicationWithExternalId(clientId, savingsProductId, ACCOUNT_TYPE_INDIVIDUAL,
interopHelper.getAccountExternalId(), true);
Assertions.assertNotNull(savingsId);
HashMap savingsStatusHashMap = SavingsStatusChecker.getStatusOfSavings(requestSpec, responseSpec, savingsId);
SavingsStatusChecker.verifySavingsIsPending(savingsStatusHashMap);
savingsStatusHashMap = savingsAccountHelper.approveSavings(savingsId);
SavingsStatusChecker.verifySavingsIsApproved(savingsStatusHashMap);
savingsStatusHashMap = savingsAccountHelper.activateSavings(savingsId);
SavingsStatusChecker.verifySavingsIsActive(savingsStatusHashMap);
if (chargeId != null) {
savingsAccountHelper.addChargesForSavings(savingsId, chargeId, false, interopHelper.getFee());
}
LOG.debug("Sucessfully created Interoperable Saving Account (id: {})", savingsId);
}
private void testParties() {
String idValue = UUID.randomUUID().toString();
String accountId = interopHelper.postParty(InteropIdentifierType.MSISDN, idValue);
Assertions.assertEquals(interopHelper.getAccountExternalId(), accountId);
interopHelper.setResponseSpec(responseForbiddenErrorSpec);
accountId = interopHelper.postParty(InteropIdentifierType.MSISDN, idValue);
Assertions.assertNull(accountId);
interopHelper.setResponseSpec(responseSpec);
accountId = interopHelper.getParty(InteropIdentifierType.MSISDN, idValue);
Assertions.assertEquals(interopHelper.getAccountExternalId(), accountId);
accountId = interopHelper.deleteParty(InteropIdentifierType.MSISDN, idValue);
Assertions.assertEquals(interopHelper.getAccountExternalId(), accountId);
interopHelper.setResponseSpec(responseNotFoundErrorSpec);
accountId = interopHelper.getParty(InteropIdentifierType.MSISDN, idValue);
Assertions.assertNull(accountId);
interopHelper.setResponseSpec(responseSpec);
}
private void testRequests() {
requestCode = UUID.randomUUID().toString();
String response = interopHelper.postTransactionRequest(requestCode, InteropTransactionRole.PAYER);
JsonPath json = JsonPath.from(response);
Assertions.assertEquals(requestCode, json.getString(InteropUtil.PARAM_REQUEST_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
interopHelper.setResponseSpec(responseClientErrorSpec);
interopHelper.postTransactionRequest(requestCode, InteropTransactionRole.PAYEE);
interopHelper.setResponseSpec(responseSpec);
}
private void testQuotes() {
// payer
quoteCode = UUID.randomUUID().toString();
String response = interopHelper.postQuote(quoteCode, InteropTransactionRole.PAYER);
JsonPath json = JsonPath.from(response);
Assertions.assertEquals(quoteCode, json.getString(InteropUtil.PARAM_QUOTE_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
Map<Object, Object> fee = json.getMap(InteropUtil.PARAM_FSP_FEE);
Assertions.assertNotNull(fee);
BigDecimal feeAmount = ObjectConverter.convertObjectTo(fee.get(InteropUtil.PARAM_AMOUNT), BigDecimal.class);
Assertions.assertTrue(MathUtil.isEqualTo(interopHelper.getFee(), feeAmount),
"Quote fee expected: " + interopHelper.getFee() + ", actual: " + feeAmount);
Assertions.assertEquals(interopHelper.getCurrency(), fee.get(InteropUtil.PARAM_CURRENCY));
// payee
response = interopHelper.postQuote(quoteCode, InteropTransactionRole.PAYEE);
json = JsonPath.from(response);
Assertions.assertEquals(quoteCode, json.getString(InteropUtil.PARAM_QUOTE_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
fee = json.getMap(InteropUtil.PARAM_FSP_FEE);
if (fee != null) {
feeAmount = ObjectConverter.convertObjectTo(fee.get(InteropUtil.PARAM_AMOUNT), BigDecimal.class);
Assertions.assertTrue(MathUtil.isZero(feeAmount), "PAYEE Quote fee expected: " + BigDecimal.ZERO + ", actual: " + feeAmount);
}
}
private void testTransfers() {
String savings = (String) savingsAccountHelper.getSavingsAccountDetail(savingsId, null);
JsonPath savingsJson = JsonPath.from(savings);
BigDecimal onHold = ObjectConverter.convertObjectTo(savingsJson.get(SavingsApiConstants.savingsAmountOnHold), BigDecimal.class);
BigDecimal balance = ObjectConverter.convertObjectTo(savingsJson.get(PARAM_ACCOUNT_BALANCE), BigDecimal.class);
transferCode = UUID.randomUUID().toString();
String response = interopHelper.prepareTransfer(transferCode);
JsonPath json = JsonPath.from(response);
Assertions.assertEquals(transferCode, json.getString(InteropUtil.PARAM_TRANSFER_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
// prepare
savings = (String) savingsAccountHelper.getSavingsAccountDetail(savingsId, null);
LOG.debug("Response Interoperable GET Saving: {}", savings);
savingsJson = JsonPath.from(savings);
BigDecimal onHold2 = ObjectConverter.convertObjectTo(savingsJson.get(SavingsApiConstants.savingsAmountOnHold), BigDecimal.class);
BigDecimal balance2 = ObjectConverter.convertObjectTo(savingsJson.get(PARAM_ACCOUNT_BALANCE), BigDecimal.class);
BigDecimal transferAmount = interopHelper.getTransferAmount();
BigDecimal expectedHold = MathUtil.add(onHold, transferAmount, MATHCONTEXT);
Assertions.assertTrue(MathUtil.isEqualTo(expectedHold, onHold2),
"On hold amount expected: " + expectedHold + ", actual: " + onHold2);
BigDecimal expectedBalance = MathUtil.subtract(balance, transferAmount, MATHCONTEXT);
Assertions.assertTrue(MathUtil.isEqualTo(expectedBalance, balance2),
"Balance amount expected: " + expectedBalance + ", actual: " + balance2);
// payer
response = interopHelper.createTransfer(transferCode, InteropTransactionRole.PAYER);
json = JsonPath.from(response);
Assertions.assertEquals(transferCode, json.getString(InteropUtil.PARAM_TRANSFER_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
savings = (String) savingsAccountHelper.getSavingsAccountDetail(savingsId, null);
LOG.debug("Response Interoperable GET Saving: {}", savings);
savingsJson = JsonPath.from(savings);
BigDecimal onHold3 = ObjectConverter.convertObjectTo(savingsJson.get(SavingsApiConstants.savingsAmountOnHold), BigDecimal.class);
BigDecimal balance3 = ObjectConverter.convertObjectTo(savingsJson.get(PARAM_ACCOUNT_BALANCE), BigDecimal.class);
Assertions.assertTrue(MathUtil.isEqualTo(onHold, onHold3), "On hold amount expected: " + onHold + ", actual: " + onHold3);
Assertions.assertTrue(MathUtil.isEqualTo(expectedBalance, balance3),
"Balance amount expected: " + expectedBalance + ", actual: " + balance3);
// payee
response = interopHelper.createTransfer(transferCode, InteropTransactionRole.PAYEE);
json = JsonPath.from(response);
Assertions.assertEquals(transferCode, json.getString(InteropUtil.PARAM_TRANSFER_CODE));
Assertions.assertEquals(InteropActionState.ACCEPTED.toString(), json.getString(InteropHelper.PARAM_ACTION_STATE));
savings = (String) savingsAccountHelper.getSavingsAccountDetail(savingsId, null);
LOG.debug("Response Interoperable GET Saving: {}", savings);
savingsJson = JsonPath.from(savings);
BigDecimal onHold4 = ObjectConverter.convertObjectTo(savingsJson.get(SavingsApiConstants.savingsAmountOnHold), BigDecimal.class);
BigDecimal balance4 = ObjectConverter.convertObjectTo(savingsJson.get(PARAM_ACCOUNT_BALANCE), BigDecimal.class);
expectedBalance = MathUtil.subtract(balance, interopHelper.getFee(), MATHCONTEXT);
Assertions.assertTrue(MathUtil.isEqualTo(onHold, onHold4), "On hold amount expected: " + onHold + ", actual: " + onHold4);
Assertions.assertTrue(MathUtil.isEqualTo(balance, balance4),
"Balance amount expected: " + expectedBalance + ", actual: " + balance4);
}
}