diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java index 2a42af23f04..60de11713bd 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/SavingsAccountChargeRoundingTest.java @@ -18,6 +18,7 @@ */ package org.apache.fineract.integrationtests; +import static org.apache.fineract.integrationtests.client.feign.modules.FeignTestConstants.DATETIME_PATTERN; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; @@ -27,37 +28,28 @@ import java.math.BigDecimal; import java.math.RoundingMode; -import java.util.List; import java.util.UUID; import lombok.extern.slf4j.Slf4j; +import org.apache.fineract.client.feign.util.CallFailedRuntimeException; import org.apache.fineract.client.models.ChargeRequest; -import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesResponse; -import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse; import org.apache.fineract.client.models.PostChargesResponse; -import org.apache.fineract.client.models.PostSavingsAccountTransactionsRequest; -import org.apache.fineract.client.models.PostSavingsAccountTransactionsResponse; import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesRequest; -import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesResponse; import org.apache.fineract.client.models.PostSavingsProductsRequest; import org.apache.fineract.client.models.SavingsAccountData; -import org.apache.fineract.client.util.CallFailedRuntimeException; -import org.apache.fineract.integrationtests.common.ClientHelper; -import org.apache.fineract.integrationtests.common.charges.ChargesHelper; -import org.apache.fineract.integrationtests.savings.base.BaseSavingsIntegrationTest; +import org.apache.fineract.integrationtests.client.feign.FeignSavingsTestBase; +import org.apache.fineract.integrationtests.common.Utils; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; @Slf4j -public class SavingsAccountChargeRoundingTest extends BaseSavingsIntegrationTest { +public class SavingsAccountChargeRoundingTest extends FeignSavingsTestBase { private Long clientId; - private ChargesHelper chargesHelper; private static final String DATE = "01 January 2026"; @BeforeEach public void setup() { - clientId = ClientHelper.createClient(ClientHelper.defaultClientCreationRequest()).getClientId(); - chargesHelper = new ChargesHelper(); + clientId = createClient(); } /** FLAT CHARGE **/ @@ -66,7 +58,7 @@ public void shouldApplyRoundingRules_forFlatCharge() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createFlatCharge(19.8); assertNotNull(charge.getResourceId()); @@ -86,7 +78,7 @@ public void shouldRoundUpFlatCharge_whenValueIsAboveHalf() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createFlatCharge(0.6); assertNotNull(charge.getResourceId()); @@ -107,7 +99,7 @@ public void shouldFailToAddFlatCharge_whenAmountRoundsToZero() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createFlatCharge(0.4); assertNotNull(charge.getResourceId()); @@ -115,8 +107,8 @@ public void shouldFailToAddFlatCharge_whenAmountRoundsToZero() { CallFailedRuntimeException exception = assertThrows(CallFailedRuntimeException.class, () -> addFlatCharge(savingsId, charge.getResourceId(), 0.4, DATE)); - assertEquals(400, exception.getResponse().code()); - assertTrue(exception.getMessage().contains("error.msg.savings.charge.amount.rounded.to.zero")); + assertEquals(400, exception.getStatus()); + assertTrue(exception.getResponseBody().contains("error.msg.savings.charge.amount.rounded.to.zero")); assertNoChargesPersisted(savingsId, charge.getResourceId()); }); } @@ -126,17 +118,17 @@ public void shouldApplyRoundingRules_forPercentageOfWithdrawalCharge() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); - deposit(savingsId, DATE, BigDecimal.valueOf(1000)); + deposit(savingsId, "1000", DATE); - withdraw(savingsId, DATE, BigDecimal.valueOf(615)); + withdraw(savingsId, "615", DATE); - SavingsAccountData accountData = getSavingsAccount(savingsId); + SavingsAccountData accountData = getSavingsDetails(savingsId); BigDecimal actualChargeFees = getActualChargeAmount(accountData); assertNotNull(actualChargeFees); @@ -158,17 +150,17 @@ public void shouldRoundUpPercentageOfWithdrawalCharge_whenValueIsAboveHalf() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); - deposit(savingsId, DATE, BigDecimal.valueOf(1000)); + deposit(savingsId, "1000", DATE); - withdraw(savingsId, DATE, BigDecimal.valueOf(24)); + withdraw(savingsId, "24", DATE); - SavingsAccountData accountData = getSavingsAccount(savingsId); + SavingsAccountData accountData = getSavingsDetails(savingsId); BigDecimal actualChargeFees = getActualChargeAmount(accountData); assertNotNull(actualChargeFees); @@ -191,17 +183,17 @@ public void shouldIgnorePercentageOfWithdrawalCharge_whenRoundedToZero() { runAt(DATE, () -> { Long productId = createSavingsProduct(0, 1); - Long savingsId = createAndActivateSavingsAccount(productId, DATE); + Long savingsId = createApproveActivateSavings(clientId, productId, DATE); PostChargesResponse charge = createPercentageWithdrawalCharge(2.5); addPercentageWithdrawalCharge(savingsId, charge.getResourceId(), 2.5); - deposit(savingsId, DATE, BigDecimal.valueOf(1000)); + deposit(savingsId, "1000", DATE); - withdraw(savingsId, DATE, BigDecimal.valueOf(20)); + withdraw(savingsId, "20", DATE); - SavingsAccountData accountData = getSavingsAccount(savingsId); + SavingsAccountData accountData = getSavingsDetails(savingsId); BigDecimal actualChargeFees = getActualChargeAmount(accountData); assertNull(actualChargeFees); @@ -218,23 +210,21 @@ public void shouldIgnorePercentageOfWithdrawalCharge_whenRoundedToZero() { // ----------------------------- private Long createSavingsProduct(int digitsAfterDecimal, int inMultiplesOf) { - return createProduct(baseSavingsProduct(digitsAfterDecimal, inMultiplesOf)).getResourceId(); + return createSavingsProduct(baseSavingsProduct(digitsAfterDecimal, inMultiplesOf)).getResourceId(); } private PostSavingsProductsRequest baseSavingsProduct(int digitsAfterDecimal, int inMultiplesOf) { - return dailyInterestPostingProduct().digitsAfterDecimal(digitsAfterDecimal).inMultiplesOf(inMultiplesOf).currencyCode("USD"); - } - - private Long createAndActivateSavingsAccount(Long productId, String date) { - Long savingsId = applySavingsAccount(applySavingsRequest(clientId, productId, date)).getSavingsId(); - approveSavingsAccount(savingsId, date); - activateSavingsAccount(savingsId, date); - return savingsId; + return new PostSavingsProductsRequest().locale("en").name(Utils.uniqueRandomStringGenerator("DAILY_INTEREST", 6)) + .shortName(Utils.uniqueRandomStringGenerator("", 4)).description("Daily interest posting product") + .nominalAnnualInterestRate(10.0).digitsAfterDecimal(digitsAfterDecimal).inMultiplesOf(inMultiplesOf).currencyCode("USD") + .accountingRule(1).interestCalculationDaysInYearType(365).interestCompoundingPeriodType(1).interestCalculationType(2) + .interestPostingPeriodType(1).withdrawalFeeForTransfers(false).enforceMinRequiredBalance(false).allowOverdraft(false) + .withHoldTax(false).isDormancyTrackingActive(false); } private PostChargesResponse createFlatCharge(double amount) { String uniqueChargeName = "Savings Account Flat Charge " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS + return chargesHelper.createCharge(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS .chargeTimeType(2) // SPECIFIED DUE DATE .chargeCalculationType(1) // FLAT .amount(amount).currencyCode("USD").locale("en").active(true).penalty(false)); @@ -242,7 +232,7 @@ private PostChargesResponse createFlatCharge(double amount) { private PostChargesResponse createPercentageWithdrawalCharge(double percentage) { String uniqueChargeName = "Savings Account Withdrawal Charge " + UUID.randomUUID().toString().replace("-", ""); - return chargesHelper.createCharges(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS + return chargesHelper.createCharge(new ChargeRequest().name(uniqueChargeName).chargeAppliesTo(2) // SAVINGS .chargeTimeType(5) // WITHDRAWAL .chargeCalculationType(2) // % OF AMOUNT .amount(percentage).currencyCode("USD").locale("en").chargePaymentMode(0).active(true).penalty(false)); @@ -252,29 +242,14 @@ private Long addFlatCharge(Long savingsId, Long chargeId, double amount, String PostSavingsAccountsSavingsAccountIdChargesRequest request = new PostSavingsAccountsSavingsAccountIdChargesRequest() .chargeId(chargeId).amount((float) amount).dateFormat(DATETIME_PATTERN).locale("en").dueDate(date); - PostSavingsAccountsSavingsAccountIdChargesResponse response = ok( - fineractClient().savingsAccountCharges.addSavingsAccountCharge(savingsId, request)); - - return response.getResourceId(); + return addSavingsAccountCharge(savingsId, request).getResourceId(); } private void addPercentageWithdrawalCharge(Long savingsId, Long chargeId, double amount) { PostSavingsAccountsSavingsAccountIdChargesRequest request = new PostSavingsAccountsSavingsAccountIdChargesRequest() .chargeId(chargeId).amount((float) amount).locale("en"); - ok(fineractClient().savingsAccountCharges.addSavingsAccountCharge(savingsId, request)); - } - - private PostSavingsAccountTransactionsResponse withdraw(Long savingsId, String date, BigDecimal amount) { - PostSavingsAccountTransactionsRequest request = new PostSavingsAccountTransactionsRequest().dateFormat(DATETIME_PATTERN) - .locale("en").paymentTypeId(1).transactionAmount(amount).transactionDate(date); - - return ok(fineractClient().savingsTransactions.createSavingsAccountTransaction(savingsId, request, "withdrawal")); - } - - private GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse getSavingsAccountCharge(Long savingsId, - Long savingsAccountChargeId) { - return ok(fineractClient().savingsAccountCharges.retrieveSavingsAccountCharge(savingsId, savingsAccountChargeId)); + addSavingsAccountCharge(savingsId, request); } private BigDecimal applyRoundingRules(BigDecimal amount, int digitsAfterDecimal, int inMultiplesOf) { @@ -339,10 +314,6 @@ private BigDecimal calculateExpectedBalance(String deposit, String withdraw, Big return new BigDecimal(deposit).subtract(new BigDecimal(withdraw)).subtract(expectedChargeFees); } - private List getSavingsCharges(Long savingsId) { - return ok(fineractClient().savingsAccountCharges.retrieveAllSavingsAccountCharges(savingsId, "all")); - } - private void assertNoChargesPersisted(Long savingsId, Long chargeId) { var charges = getSavingsCharges(savingsId); boolean chargeExists = charges.stream().anyMatch(c -> chargeId.equals(c.getChargeId())); diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignSavingsTestBase.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignSavingsTestBase.java index 7300db26935..12893f18871 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignSavingsTestBase.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/FeignSavingsTestBase.java @@ -21,23 +21,31 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; +import java.util.List; import java.util.function.Function; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.models.DeleteSavingsAccountsAccountIdResponse; +import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesResponse; +import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse; import org.apache.fineract.client.models.GetSavingsProductsProductIdResponse; import org.apache.fineract.client.models.PostSavingsAccountTransactionsResponse; import org.apache.fineract.client.models.PostSavingsAccountsAccountIdResponse; import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesRequest; +import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesResponse; import org.apache.fineract.client.models.PostSavingsProductsRequest; import org.apache.fineract.client.models.PostSavingsProductsResponse; import org.apache.fineract.client.models.SavingsAccountData; import org.apache.fineract.client.models.SavingsAccountStatusEnumData; import org.apache.fineract.integrationtests.client.FeignIntegrationTest; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignBusinessDateHelper; +import org.apache.fineract.integrationtests.client.feign.helpers.FeignChargesHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignClientHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsLifecycleExtension; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsProductHelper; import org.apache.fineract.integrationtests.client.feign.helpers.FeignSavingsTransactionHelper; +import org.apache.fineract.integrationtests.client.feign.modules.LoanTestData; import org.apache.fineract.integrationtests.common.FineractFeignClientHelper; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.extension.ExtendWith; @@ -49,6 +57,8 @@ public abstract class FeignSavingsTestBase extends FeignIntegrationTest { protected static FeignSavingsTransactionHelper savingsTransactionHelper; protected static FeignSavingsProductHelper savingsProductHelper; protected static FeignClientHelper clientHelper; + protected static FeignChargesHelper chargesHelper; + protected static FeignBusinessDateHelper businessDateHelper; @BeforeAll public static void setupSavingsHelpers() { @@ -57,6 +67,8 @@ public static void setupSavingsHelpers() { savingsTransactionHelper = new FeignSavingsTransactionHelper(client); savingsProductHelper = new FeignSavingsProductHelper(client); clientHelper = new FeignClientHelper(client); + chargesHelper = new FeignChargesHelper(client); + businessDateHelper = new FeignBusinessDateHelper(client); } protected Long createClient() { @@ -120,4 +132,26 @@ protected void verifySavingsStatus(Long savingsId, Function getSavingsCharges(Long savingsId) { + return savingsHelper.getSavingsCharges(savingsId); + } } diff --git a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignSavingsHelper.java b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignSavingsHelper.java index ac4a8aa1bd0..2a551809b01 100644 --- a/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignSavingsHelper.java +++ b/integration-tests/src/test/java/org/apache/fineract/integrationtests/client/feign/helpers/FeignSavingsHelper.java @@ -20,13 +20,18 @@ import static org.apache.fineract.client.feign.util.FeignCalls.ok; +import java.util.List; import java.util.Map; import org.apache.fineract.client.feign.FineractFeignClient; import org.apache.fineract.client.models.DeleteSavingsAccountsAccountIdResponse; +import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesResponse; +import org.apache.fineract.client.models.GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse; import org.apache.fineract.client.models.PostSavingsAccountsAccountIdRequest; import org.apache.fineract.client.models.PostSavingsAccountsAccountIdResponse; import org.apache.fineract.client.models.PostSavingsAccountsRequest; import org.apache.fineract.client.models.PostSavingsAccountsResponse; +import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesRequest; +import org.apache.fineract.client.models.PostSavingsAccountsSavingsAccountIdChargesResponse; import org.apache.fineract.client.models.SavingsAccountData; import org.apache.fineract.client.models.SavingsAccountSummaryData; import org.apache.fineract.integrationtests.client.feign.modules.SavingsRequestBuilders; @@ -94,4 +99,18 @@ public Long createApproveActivateSavings(Long clientId, Long productId, String d activateSavings(savingsId, date); return savingsId; } + + public PostSavingsAccountsSavingsAccountIdChargesResponse addSavingsAccountCharge(Long savingsId, + PostSavingsAccountsSavingsAccountIdChargesRequest request) { + return ok(() -> fineractClient.savingsCharges().createSavingsAccountCharge(savingsId, request)); + } + + public GetSavingsAccountsSavingsAccountIdChargesSavingsAccountChargeIdResponse getSavingsAccountCharge(Long savingsId, + Long savingsAccountChargeId) { + return ok(() -> fineractClient.savingsCharges().retrieveOneSavingsAccountCharge(savingsId, savingsAccountChargeId)); + } + + public List getSavingsCharges(Long savingsId) { + return ok(() -> fineractClient.savingsCharges().retrieveAllSavingsAccountCharges(savingsId, "all")); + } }