Filter for instances read, write, batch
This commit is contained in:
committed by
Arnold Gálovics
parent
ee1f988be6
commit
ebf0e8b539
@@ -58,10 +58,13 @@ jobs:
|
||||
sudo apt-get install ghostscript graphviz -y
|
||||
|
||||
- name: Basic Auth Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test
|
||||
|
||||
- name: 2FA Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast
|
||||
|
||||
- name: OAuth2 Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast
|
||||
|
||||
- name: Instance Mode & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast
|
||||
|
||||
@@ -58,10 +58,13 @@ jobs:
|
||||
sudo apt-get install ghostscript graphviz -y
|
||||
|
||||
- name: Basic Auth Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -PdbType=mysql
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test -PdbType=mysql
|
||||
|
||||
- name: 2FA Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast -PdbType=mysql
|
||||
|
||||
- name: OAuth2 Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast -PdbType=mysql
|
||||
|
||||
- name: Instance Mode & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast -PdbType=mysql
|
||||
|
||||
@@ -59,10 +59,13 @@ jobs:
|
||||
sudo apt-get install ghostscript graphviz -y
|
||||
|
||||
- name: Basic Auth Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -PdbType=postgresql
|
||||
run: ./gradlew --no-daemon -q --console=plain build test --fail-fast doc -x :twofactor-tests:test -x :oauth2-test:test -x :instancemode-tests:test -PdbType=postgresql
|
||||
|
||||
- name: 2FA Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :twofactor-tests:test --fail-fast -PdbType=postgresql
|
||||
|
||||
- name: OAuth2 Build & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :oauth2-tests:test --fail-fast -PdbType=postgresql
|
||||
|
||||
- name: Instance Mode & Test
|
||||
run: ./gradlew --no-daemon -q --console=plain :instancemode-tests:test --fail-fast -PdbType=postgresql
|
||||
|
||||
@@ -30,6 +30,7 @@ buildscript {
|
||||
'integration-tests',
|
||||
'twofactor-tests',
|
||||
'oauth2-tests',
|
||||
'instancemode-tests',
|
||||
'fineract-client',
|
||||
'core',
|
||||
'service',
|
||||
|
||||
+20
@@ -60,5 +60,25 @@ public class FineractProperties {
|
||||
public boolean isReadOnlyMode() {
|
||||
return readEnabled && !writeEnabled && !batchEnabled;
|
||||
}
|
||||
|
||||
public boolean isWriteOnlyMode() {
|
||||
return !readEnabled && writeEnabled && !batchEnabled;
|
||||
}
|
||||
|
||||
public boolean isBatchOnlyMode() {
|
||||
return !readEnabled && !writeEnabled && batchEnabled;
|
||||
}
|
||||
|
||||
public boolean isReadInstance() {
|
||||
return isReadOnlyMode() || readEnabled;
|
||||
}
|
||||
|
||||
public boolean isWriteInstance() {
|
||||
return isWriteOnlyMode() || writeEnabled;
|
||||
}
|
||||
|
||||
public boolean isBatchInstance() {
|
||||
return isBatchOnlyMode() || batchEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
-1
@@ -19,6 +19,7 @@
|
||||
|
||||
package org.apache.fineract.infrastructure.core.config;
|
||||
|
||||
import org.apache.fineract.infrastructure.security.filter.FineractInstanceModeApiFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TenantAwareBasicAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.filter.TwoFactorAuthenticationFilter;
|
||||
import org.apache.fineract.infrastructure.security.service.TenantAwareJpaPlatformUserDetailsService;
|
||||
@@ -53,6 +54,12 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Autowired
|
||||
private TwoFactorAuthenticationFilter twoFactorAuthenticationFilter;
|
||||
|
||||
@Autowired
|
||||
private FineractInstanceModeApiFilter fineractInstanceModeApiFilter;
|
||||
|
||||
@Autowired
|
||||
private FineractProperties fineractProperties;
|
||||
|
||||
@Autowired
|
||||
private ServerProperties serverProperties;
|
||||
|
||||
@@ -77,7 +84,8 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.sessionManagement() //
|
||||
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) //
|
||||
.and() //
|
||||
.addFilterAfter(tenantAwareBasicAuthenticationFilter(), SecurityContextPersistenceFilter.class) //
|
||||
.addFilterAfter(fineractInstanceModeApiFilter, SecurityContextPersistenceFilter.class) //
|
||||
.addFilterAfter(tenantAwareBasicAuthenticationFilter(), FineractInstanceModeApiFilter.class) //
|
||||
.addFilterAfter(twoFactorAuthenticationFilter, BasicAuthenticationFilter.class); //
|
||||
|
||||
if (serverProperties.getSsl().isEnabled()) {
|
||||
|
||||
+19
-4
@@ -19,8 +19,10 @@
|
||||
package org.apache.fineract.infrastructure.core.data;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.google.gson.Gson;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
|
||||
/**
|
||||
*
|
||||
@@ -72,7 +74,17 @@ public class ApiGlobalErrorResponse {
|
||||
globalErrorResponse.setHttpStatusCode("401");
|
||||
globalErrorResponse.setDeveloperMessage("Invalid tenant details were passed in api request.");
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.tenant.identifier");
|
||||
globalErrorResponse.setDefaultUserMessage("Invalide tenant identifier provided with request.");
|
||||
globalErrorResponse.setDefaultUserMessage("Invalid tenant identifier provided with request.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
public static ApiGlobalErrorResponse invalidInstanceTypeMethod(final String method) {
|
||||
final ApiGlobalErrorResponse globalErrorResponse = new ApiGlobalErrorResponse();
|
||||
globalErrorResponse.setHttpStatusCode(Status.METHOD_NOT_ALLOWED.toString());
|
||||
globalErrorResponse.setDeveloperMessage("Invalid instance type called in api request for the method " + method);
|
||||
globalErrorResponse.setUserMessageGlobalisationCode("error.msg.invalid.instance.type");
|
||||
globalErrorResponse.setDefaultUserMessage("Invalid method " + method + " used with request to this instance type.");
|
||||
|
||||
return globalErrorResponse;
|
||||
}
|
||||
@@ -186,9 +198,7 @@ public class ApiGlobalErrorResponse {
|
||||
return globalErrorResponse;
|
||||
}
|
||||
|
||||
protected ApiGlobalErrorResponse() {
|
||||
//
|
||||
}
|
||||
protected ApiGlobalErrorResponse() {}
|
||||
|
||||
public ApiGlobalErrorResponse(final List<ApiParameterError> errors) {
|
||||
this.errors = errors;
|
||||
@@ -234,4 +244,9 @@ public class ApiGlobalErrorResponse {
|
||||
public void setUserMessageGlobalisationCode(final String userMessageGlobalisationCode) {
|
||||
this.userMessageGlobalisationCode = userMessageGlobalisationCode;
|
||||
}
|
||||
|
||||
public String toJson() {
|
||||
final Gson gson = new Gson();
|
||||
return gson.toJson(this);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-26
@@ -39,12 +39,16 @@ import javax.ws.rs.QueryParam;
|
||||
import javax.ws.rs.core.Context;
|
||||
import javax.ws.rs.core.MediaType;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.core.Response.Status;
|
||||
import javax.ws.rs.core.UriInfo;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.fineract.commands.domain.CommandWrapper;
|
||||
import org.apache.fineract.commands.service.CommandWrapperBuilder;
|
||||
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
|
||||
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
||||
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.apache.fineract.infrastructure.core.exception.UnrecognizedQueryParamException;
|
||||
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
|
||||
@@ -57,13 +61,13 @@ import org.apache.fineract.infrastructure.jobs.service.JobRegisterService;
|
||||
import org.apache.fineract.infrastructure.jobs.service.SchedulerJobRunnerReadService;
|
||||
import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
|
||||
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
@Path("/jobs")
|
||||
@Consumes({ MediaType.APPLICATION_JSON })
|
||||
@Produces({ MediaType.APPLICATION_JSON })
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
@Tag(name = "MIFOSX-BATCH JOBS", description = "Batch jobs (also known as cron jobs on Unix-based systems) are a series of back-end jobs executed on a computer at a particular time defined in job's cron expression.\n\n At any point, you can view the list of batch jobs scheduled to run along with other details specific to each job. Manually you can execute the jobs at any point of time.\n\n The scheduler status can be either \"Active\" or \"Standby\". If the scheduler status is Active, it indicates that all batch jobs are running/ will run as per the specified schedule.If the scheduler status is Standby, it will ensure all scheduled batch runs are suspended.")
|
||||
public class SchedulerJobApiResource {
|
||||
|
||||
@@ -74,21 +78,7 @@ public class SchedulerJobApiResource {
|
||||
private final ToApiJsonSerializer<JobDetailHistoryData> jobHistoryToApiJsonSerializer;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final PlatformSecurityContext context;
|
||||
|
||||
@Autowired
|
||||
public SchedulerJobApiResource(final SchedulerJobRunnerReadService schedulerJobRunnerReadService,
|
||||
final JobRegisterService jobRegisterService, final ToApiJsonSerializer<JobDetailData> toApiJsonSerializer,
|
||||
final ApiRequestParameterHelper apiRequestParameterHelper,
|
||||
final ToApiJsonSerializer<JobDetailHistoryData> jobHistoryToApiJsonSerializer,
|
||||
final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, final PlatformSecurityContext context) {
|
||||
this.schedulerJobRunnerReadService = schedulerJobRunnerReadService;
|
||||
this.jobRegisterService = jobRegisterService;
|
||||
this.toApiJsonSerializer = toApiJsonSerializer;
|
||||
this.jobHistoryToApiJsonSerializer = jobHistoryToApiJsonSerializer;
|
||||
this.apiRequestParameterHelper = apiRequestParameterHelper;
|
||||
this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
|
||||
this.context = context;
|
||||
}
|
||||
private final FineractProperties fineractProperties;
|
||||
|
||||
@GET
|
||||
@Operation(summary = "Retrieve Scheduler Jobs", description = "Returns the list of jobs.\n" + "\n" + "Example Requests:\n" + "\n"
|
||||
@@ -142,17 +132,24 @@ public class SchedulerJobApiResource {
|
||||
public Response executeJob(@PathParam(SchedulerJobApiConstants.JOB_ID) @Parameter(description = "jobId") final Long jobId,
|
||||
@QueryParam(SchedulerJobApiConstants.COMMAND) @Parameter(description = "command") final String commandParam) {
|
||||
// check the logged in user have permissions to execute scheduler jobs
|
||||
final boolean hasNotPermission = this.context.authenticatedUser().hasNotPermissionForAnyOf("ALL_FUNCTIONS", "EXECUTEJOB_SCHEDULER");
|
||||
if (hasNotPermission) {
|
||||
final String authorizationMessage = "User has no authority to execute scheduler jobs";
|
||||
throw new NoAuthorizationException(authorizationMessage);
|
||||
}
|
||||
Response response = Response.status(400).build();
|
||||
if (is(commandParam, SchedulerJobApiConstants.COMMAND_EXECUTE_JOB)) {
|
||||
this.jobRegisterService.executeJob(jobId);
|
||||
response = Response.status(202).build();
|
||||
Response response;
|
||||
if (fineractProperties.getMode().isBatchInstance()) {
|
||||
final boolean hasNotPermission = this.context.authenticatedUser().hasNotPermissionForAnyOf("ALL_FUNCTIONS",
|
||||
"EXECUTEJOB_SCHEDULER");
|
||||
if (hasNotPermission) {
|
||||
final String authorizationMessage = "User has no authority to execute scheduler jobs";
|
||||
throw new NoAuthorizationException(authorizationMessage);
|
||||
}
|
||||
response = Response.status(400).build();
|
||||
if (is(commandParam, SchedulerJobApiConstants.COMMAND_EXECUTE_JOB)) {
|
||||
this.jobRegisterService.executeJob(jobId);
|
||||
response = Response.status(202).build();
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException(SchedulerJobApiConstants.COMMAND, commandParam);
|
||||
}
|
||||
} else {
|
||||
throw new UnrecognizedQueryParamException(SchedulerJobApiConstants.COMMAND, commandParam);
|
||||
ApiGlobalErrorResponse errorResponse = ApiGlobalErrorResponse.invalidInstanceTypeMethod("Batch");
|
||||
response = Response.status(Status.METHOD_NOT_ALLOWED).entity(errorResponse).build();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
+4
@@ -97,6 +97,10 @@ public class JobRegisterServiceImpl implements JobRegisterService, ApplicationLi
|
||||
|
||||
@PostConstruct
|
||||
public void loadAllJobs() {
|
||||
// If the instance is not Batch Enabled will not load the Jobs
|
||||
if (!fineractProperties.getMode().isBatchEnabled()) {
|
||||
return;
|
||||
}
|
||||
final List<FineractPlatformTenant> allTenants = this.tenantDetailsService.findAllTenants();
|
||||
for (final FineractPlatformTenant tenant : allTenants) {
|
||||
ThreadLocalContextUtil.setTenant(tenant);
|
||||
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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.infrastructure.security.exception;
|
||||
|
||||
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
|
||||
|
||||
/**
|
||||
* {@link RuntimeException} thrown when an invalid method in the Fineract instance type called in request to platform.
|
||||
*
|
||||
*
|
||||
*/
|
||||
public class InvalidInstanceTypeMethodException extends AbstractPlatformDomainRuleException {
|
||||
|
||||
public InvalidInstanceTypeMethodException(final String method) {
|
||||
super("error.msg.invalid.method.for.instance.type", "Method Not Allowed " + method + " for the instance type");
|
||||
}
|
||||
}
|
||||
+62
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* 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.infrastructure.security.filter;
|
||||
|
||||
import java.io.IOException;
|
||||
import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.ws.rs.HttpMethod;
|
||||
import javax.ws.rs.ext.Provider;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import org.apache.fineract.infrastructure.core.config.FineractProperties;
|
||||
import org.apache.fineract.infrastructure.core.data.ApiGlobalErrorResponse;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.filter.OncePerRequestFilter;
|
||||
|
||||
@Provider
|
||||
@Component
|
||||
@RequiredArgsConstructor
|
||||
public class FineractInstanceModeApiFilter extends OncePerRequestFilter {
|
||||
|
||||
private final FineractProperties fineractProperties;
|
||||
|
||||
@Override
|
||||
protected void doFilterInternal(final HttpServletRequest request, final HttpServletResponse response, final FilterChain filterChain)
|
||||
throws ServletException, IOException {
|
||||
|
||||
if (fineractProperties.getMode().isReadInstance() && isReadMethod(request)) {
|
||||
filterChain.doFilter(request, response);
|
||||
} else if (fineractProperties.getMode().isWriteInstance()) {
|
||||
filterChain.doFilter(request, response);
|
||||
} else if (fineractProperties.getMode().isBatchInstance() && request.getPathInfo().startsWith("/jobs")) {
|
||||
filterChain.doFilter(request, response);
|
||||
} else {
|
||||
response.setStatus(HttpStatus.SC_METHOD_NOT_ALLOWED);
|
||||
ApiGlobalErrorResponse errorResponse = ApiGlobalErrorResponse.invalidInstanceTypeMethod(request.getMethod());
|
||||
response.getWriter().write(errorResponse.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isReadMethod(HttpServletRequest request) {
|
||||
return HttpMethod.GET.equals(request.getMethod());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
description = 'Fineract Instance Type Tests'
|
||||
|
||||
apply plugin: 'com.bmuschko.cargo'
|
||||
|
||||
// Configuration for the Gradle Cargo plugin
|
||||
// https://github.com/bmuschko/gradle-cargo-plugin
|
||||
configurations {
|
||||
tomcat
|
||||
}
|
||||
|
||||
apply from: 'dependencies.gradle'
|
||||
|
||||
// enable when all tests are migrated
|
||||
tasks.cucumber.onlyIf {false}
|
||||
|
||||
// Allow external drivers to be used for the tests without packaging it
|
||||
// mainly due to license incompatibilities
|
||||
configurations {
|
||||
driver
|
||||
}
|
||||
dependencies {
|
||||
driver 'mysql:mysql-connector-java:8.0.29'
|
||||
}
|
||||
|
||||
cargo {
|
||||
containerId "tomcat9x"
|
||||
|
||||
// looks like Cargo doesn't detect the WAR file automatically in the multi-module setup
|
||||
deployable {
|
||||
file = file("$rootDir/fineract-war/build/libs/fineract-provider.war")
|
||||
context = 'fineract-provider'
|
||||
}
|
||||
|
||||
local {
|
||||
logLevel = 'high'
|
||||
outputFile = file('build/output.log')
|
||||
installer {
|
||||
installConfiguration = configurations.tomcat
|
||||
downloadDir = file("$buildDir/download")
|
||||
extractDir = file("$buildDir/tomcat")
|
||||
}
|
||||
startStopTimeout = 960000
|
||||
sharedClasspath = configurations.driver
|
||||
containerProperties {
|
||||
def jvmArgs = '--add-exports=java.naming/com.sun.jndi.ldap=ALL-UNNAMED --add-opens=java.base/java.lang=ALL-UNNAMED --add-opens=java.base/java.lang.invoke=ALL-UNNAMED --add-opens=java.base/java.io=ALL-UNNAMED --add-opens=java.base/java.security=ALL-UNNAMED --add-opens=java.base/java.util=ALL-UNNAMED --add-opens=java.management/javax.management=ALL-UNNAMED --add-opens=java.naming/javax.naming=ALL-UNNAMED '
|
||||
if (project.hasProperty('localDebug')) {
|
||||
jvmArgs += ' -agentlib:jdwp=transport=dt_socket,server=y,address=*:9000,suspend=n -Xmx2G -Duser.timezone=Asia/Kolkata '
|
||||
}
|
||||
if (project.hasProperty('dbType')) {
|
||||
if ('postgresql'.equalsIgnoreCase(dbType)) {
|
||||
jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.postgresql.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:postgresql://localhost:5432/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=postgres -Dfineract.tenant.host=localhost -Dfineract.tenant.port=5432 -Dfineract.tenant.username=root -Dfineract.tenant.password=postgres'
|
||||
} else if ('mysql'.equalsIgnoreCase(dbType)) {
|
||||
jvmArgs += '-Dspring.datasource.hikari.driverClassName=com.mysql.cj.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mysql://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql'
|
||||
} else {
|
||||
throw new GradleException('Provided dbType is not supported')
|
||||
}
|
||||
} else {
|
||||
jvmArgs += '-Dspring.datasource.hikari.driverClassName=org.mariadb.jdbc.Driver -Dspring.datasource.hikari.jdbcUrl=jdbc:mariadb://localhost:3306/fineract_tenants -Dspring.datasource.hikari.username=root -Dspring.datasource.hikari.password=mysql -Dfineract.tenant.host=localhost -Dfineract.tenant.port=3306 -Dfineract.tenant.username=root -Dfineract.tenant.password=mysql'
|
||||
}
|
||||
if (project.hasProperty('instanceMode')) {
|
||||
if ('readOnly'.equalsIgnoreCase(instanceMode)) {
|
||||
jvmArgs += ' -Dfineract.mode.write-enabled=false -Dfineract.mode.batch-enabled=false'
|
||||
} else if ('batchOnly'.equalsIgnoreCase(instanceMode)) {
|
||||
jvmArgs += ' -Dfineract.mode.write-enabled=false -Dfineract.mode.read-enabled=false'
|
||||
} else {
|
||||
jvmArgs += ' -Dfineract.mode.read-enabled=false -Dfineract.mode.batch-enabled=false'
|
||||
}
|
||||
} else {
|
||||
jvmArgs += ' -Dfineract.mode.read-enabled=false -Dfineract.mode.batch-enabled=false'
|
||||
}
|
||||
|
||||
property 'cargo.start.jvmargs', jvmArgs
|
||||
property 'cargo.tomcat.connector.keystoreFile', file("$rootDir/fineract-provider/src/main/resources/keystore.jks")
|
||||
property 'cargo.tomcat.connector.keystorePass', 'openmf'
|
||||
property 'cargo.tomcat.httpSecure', true
|
||||
property 'cargo.tomcat.connector.sslProtocol', 'TLS'
|
||||
property 'cargo.tomcat.connector.clientAuth', false
|
||||
property 'cargo.protocol', 'https'
|
||||
property 'cargo.servlet.port', 8443
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cargoRunLocal.dependsOn ':fineract-war:war'
|
||||
cargoStartLocal.dependsOn ':fineract-war:war'
|
||||
cargoStartLocal.mustRunAfter 'testClasses'
|
||||
|
||||
test {
|
||||
dependsOn (cargoStartLocal)
|
||||
finalizedBy cargoStopLocal
|
||||
}
|
||||
|
||||
// NOTE: Gradle suggested these dependencies
|
||||
compileTestJava.dependsOn(':fineract-provider:generateGitProperties', ':fineract-provider:processResources', ':fineract-provider:resolve')
|
||||
spotbugsTest.dependsOn(':fineract-provider:generateGitProperties', ':fineract-provider:processResources', ':fineract-provider:resolve')
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
dependencies {
|
||||
// testCompile dependencies are ONLY used in src/test, not src/main.
|
||||
// Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly!
|
||||
//
|
||||
tomcat 'org.apache.tomcat:tomcat:9.0.62@zip'
|
||||
testImplementation( files("$rootDir/fineract-provider/build/classes/java/main/"),
|
||||
project(path: ':fineract-provider', configuration: 'runtimeElements'),
|
||||
'io.cucumber:cucumber-spring',
|
||||
'com.intuit.karate:karate-junit5',
|
||||
// 'com.google.code.gson:gson',
|
||||
)
|
||||
testImplementation ('org.mock-server:mockserver-junit-jupiter') {
|
||||
exclude group: 'com.sun.mail', module: 'mailapi'
|
||||
exclude group: 'javax.servlet', module: 'javax.servlet-api'
|
||||
exclude group: 'javax.validation'
|
||||
}
|
||||
testImplementation ('io.rest-assured:rest-assured') {
|
||||
exclude group: 'commons-logging'
|
||||
exclude group: 'org.apache.sling'
|
||||
exclude group: 'com.sun.xml.bind'
|
||||
}
|
||||
|
||||
testCompileOnly 'org.projectlombok:lombok'
|
||||
testAnnotationProcessor 'org.projectlombok:lombok'
|
||||
}
|
||||
+199
@@ -0,0 +1,199 @@
|
||||
/**
|
||||
* 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;
|
||||
|
||||
import static io.restassured.RestAssured.given;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
import static org.hamcrest.Matchers.is;
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
import static org.junit.jupiter.api.Assertions.assertNotNull;
|
||||
import static org.junit.jupiter.api.Assertions.fail;
|
||||
|
||||
import com.google.gson.Gson;
|
||||
import io.restassured.RestAssured;
|
||||
import io.restassured.builder.RequestSpecBuilder;
|
||||
import io.restassured.builder.ResponseSpecBuilder;
|
||||
import io.restassured.http.ContentType;
|
||||
import io.restassured.path.json.JsonPath;
|
||||
import io.restassured.response.Response;
|
||||
import io.restassured.specification.RequestSpecification;
|
||||
import io.restassured.specification.ResponseSpecification;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.apache.http.HttpStatus;
|
||||
import org.apache.http.conn.HttpHostConnectException;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
public class BatchInstanceModeTest {
|
||||
|
||||
private ResponseSpecification responseSpec200;
|
||||
private ResponseSpecification responseSpec405;
|
||||
private RequestSpecification requestSpec;
|
||||
|
||||
private static final String TENANT_PARAM_NAME = "tenantIdentifier";
|
||||
private static final String DEFAULT_TENANT = "default";
|
||||
private static final String TENANT_IDENTIFIER = TENANT_PARAM_NAME + '=' + DEFAULT_TENANT;
|
||||
|
||||
private static final String HEALTH_URL = "/fineract-provider/actuator/health";
|
||||
private static final String LOGIN_URL = "/fineract-provider/api/v1/authentication?" + TENANT_IDENTIFIER;
|
||||
private static final String JOBS_URL = "/fineract-provider/api/v1/jobs";
|
||||
private static final String OFFICES_URL = "/fineract-provider/api/v1/offices";
|
||||
|
||||
@BeforeEach
|
||||
public void setup() throws InterruptedException {
|
||||
initializeRestAssured();
|
||||
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
|
||||
// Login with basic authentication
|
||||
awaitSpringBootActuatorHealthyUp();
|
||||
this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
|
||||
this.responseSpec200 = new ResponseSpecBuilder().expectStatusCode(200).build();
|
||||
this.responseSpec405 = new ResponseSpecBuilder().expectStatusCode(405).build();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptWriteRequestWhenIsWriteOnly() {
|
||||
loginIntoServerAndGetBase64EncodedAuthenticationKey(requestSpec, responseSpec200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void acceptReadRequestWhenIsWriteOnly() {
|
||||
this.requestSpec.header("Authorization",
|
||||
"Basic " + loginIntoServerAndGetBase64EncodedAuthenticationKey(requestSpec, responseSpec200));
|
||||
final int statusCode = getHeadOffice(requestSpec, responseSpec200);
|
||||
assertEquals(HttpStatus.SC_OK, statusCode);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rejectBatchJobRequestWhenIsWriteOnly() {
|
||||
this.requestSpec.header("Authorization",
|
||||
"Basic " + loginIntoServerAndGetBase64EncodedAuthenticationKey(requestSpec, responseSpec200));
|
||||
|
||||
final String GET_ALL_SCHEDULER_JOBS_URL = JOBS_URL + "?" + TENANT_IDENTIFIER;
|
||||
List<Map<String, Object>> allSchedulerJobsData = getAllSchedulerJobs(requestSpec, responseSpec200, GET_ALL_SCHEDULER_JOBS_URL);
|
||||
assertNotNull(allSchedulerJobsData);
|
||||
final String jobName = "Add Accrual Transactions";
|
||||
final int jobId = this.getSchedulerJobIdByName(allSchedulerJobsData, jobName);
|
||||
final int statusCode = runSchedulerJob(requestSpec, responseSpec405, jobId);
|
||||
assertEquals(HttpStatus.SC_METHOD_NOT_ALLOWED, statusCode);
|
||||
}
|
||||
|
||||
private static void initializeRestAssured() {
|
||||
RestAssured.baseURI = "https://localhost";
|
||||
RestAssured.port = 8443;
|
||||
RestAssured.keyStore("src/main/resources/keystore.jks", "openmf");
|
||||
RestAssured.useRelaxedHTTPSValidation();
|
||||
}
|
||||
|
||||
private static void awaitSpringBootActuatorHealthyUp() throws InterruptedException {
|
||||
int attempt = 0;
|
||||
final int max_attempts = 10;
|
||||
Response response = null;
|
||||
|
||||
do {
|
||||
try {
|
||||
response = RestAssured.get(HEALTH_URL);
|
||||
|
||||
if (response.statusCode() == 200) {
|
||||
return;
|
||||
}
|
||||
|
||||
Thread.sleep(3000);
|
||||
} catch (Exception e) {
|
||||
Thread.sleep(3000);
|
||||
}
|
||||
} while (attempt < max_attempts);
|
||||
|
||||
fail(HEALTH_URL + " returned " + response.prettyPrint());
|
||||
}
|
||||
|
||||
private static String loginIntoServerAndGetBase64EncodedAuthenticationKey(final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec) {
|
||||
try {
|
||||
String json = given().spec(requestSpec).body("{\"username\":\"mifos\", \"password\":\"password\"}").expect().spec(responseSpec)
|
||||
.log().ifError().when().post(LOGIN_URL).asString();
|
||||
assertThat("Failed to login into fineract platform", StringUtils.isBlank(json), is(false));
|
||||
String key = JsonPath.with(json).get("base64EncodedAuthenticationKey");
|
||||
assertThat("Failed to obtain key: " + json, StringUtils.isBlank(key), is(false));
|
||||
return key;
|
||||
} catch (final Exception e) {
|
||||
if (e instanceof HttpHostConnectException) {
|
||||
final HttpHostConnectException hh = (HttpHostConnectException) e;
|
||||
fail("Failed to connect to fineract platform:" + hh.getMessage());
|
||||
}
|
||||
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private int getHeadOffice(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
|
||||
return performServerGet(requestSpec, responseSpec, OFFICES_URL + "/1?" + TENANT_IDENTIFIER);
|
||||
}
|
||||
|
||||
private List<Map<String, Object>> getAllSchedulerJobs(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final String getURL) {
|
||||
List<Map<String, Object>> response = performServerGet(requestSpec, responseSpec, getURL, "");
|
||||
assertNotNull(response);
|
||||
return response;
|
||||
}
|
||||
|
||||
private int getSchedulerJobIdByName(List<Map<String, Object>> allSchedulerJobsData, String jobName) {
|
||||
for (Integer jobIndex = 0; jobIndex < allSchedulerJobsData.size(); jobIndex++) {
|
||||
if (allSchedulerJobsData.get(jobIndex).get("displayName").equals(jobName)) {
|
||||
return (Integer) allSchedulerJobsData.get(jobIndex).get("jobId");
|
||||
}
|
||||
}
|
||||
throw new IllegalArgumentException(
|
||||
"No such named Job (see org.apache.fineract.infrastructure.jobs.service.JobName enum):" + jobName);
|
||||
}
|
||||
|
||||
private static String runSchedulerJobAsJSON() {
|
||||
final Map<String, String> map = new HashMap<>();
|
||||
String runSchedulerJob = new Gson().toJson(map);
|
||||
return runSchedulerJob;
|
||||
}
|
||||
|
||||
private int runSchedulerJob(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final int jobId) {
|
||||
final String RUN_SCHEDULER_JOB_URL = JOBS_URL + "/" + jobId + "?command=executeJob&" + TENANT_IDENTIFIER;
|
||||
return performServerPost(requestSpec, responseSpec, RUN_SCHEDULER_JOB_URL, runSchedulerJobAsJSON());
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private static <T> T performServerGet(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
|
||||
final String getURL, final String jsonAttributeToGetBack) {
|
||||
final String json = given().spec(requestSpec).expect().spec(responseSpec).log().ifError().when().get(getURL).andReturn().asString();
|
||||
if (jsonAttributeToGetBack == null) {
|
||||
return (T) json;
|
||||
}
|
||||
return (T) JsonPath.from(json).get(jsonAttributeToGetBack);
|
||||
}
|
||||
|
||||
private int performServerGet(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String getURL) {
|
||||
return given().spec(requestSpec).expect().spec(responseSpec).when().get(getURL).getStatusCode();
|
||||
}
|
||||
|
||||
private int performServerPost(final RequestSpecification requestSpec, final ResponseSpecification responseSpec, final String postURL,
|
||||
final String jsonBodyToSend) {
|
||||
return given().spec(requestSpec).body(jsonBodyToSend).expect().spec(responseSpec).when().post(postURL).getStatusCode();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
cucumber.publish.quiet=true
|
||||
cucumber.glue=org.apache.fineract
|
||||
@@ -0,0 +1,20 @@
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
|
||||
junit.jupiter.testclass.order.default = org.junit.jupiter.api.ClassOrderer$OrderAnnotation
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 2.0 MiB |
+171
-171
@@ -1167,72 +1167,6 @@ public class FixedDepositTest {
|
||||
Assertions.assertNotNull(fixedDepositAccountId);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaturityAmountForMonthlyCompoundingAndMonthlyPosting_With_365_Days() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
|
||||
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
|
||||
DateFormat currentDateFormat = new SimpleDateFormat("dd");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -3);
|
||||
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.YEAR, 10);
|
||||
final String VALID_TO = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
|
||||
todaysDate.add(Calendar.DATE, -(currentDate - 1));
|
||||
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
dateFormat.format(todaysDate.getTime());
|
||||
monthDayFormat.format(todaysDate.getTime());
|
||||
|
||||
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(clientId);
|
||||
|
||||
final String accountingRule = NONE;
|
||||
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule);
|
||||
Assertions.assertNotNull(fixedDepositProductId);
|
||||
|
||||
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(),
|
||||
SUBMITTED_ON_DATE, WHOLE_TERM);
|
||||
Assertions.assertNotNull(fixedDepositAccountId);
|
||||
|
||||
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
|
||||
|
||||
HashMap fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
Float principal = (Float) fixedDepositAccountData.get("depositAmount");
|
||||
Float maturityAmount = (Float) fixedDepositAccountData.get("maturityAmount");
|
||||
Integer depositPeriod = (Integer) fixedDepositAccountData.get("depositPeriod");
|
||||
HashMap daysInYearMap = (HashMap) fixedDepositAccountData.get("interestCalculationDaysInYearType");
|
||||
Integer daysInYear = (Integer) daysInYearMap.get("id");
|
||||
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
|
||||
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
|
||||
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositPeriod);
|
||||
double interestRateInFraction = interestRate / 100;
|
||||
double perDay = (double) 1 / daysInYear;
|
||||
LOG.info("per day = {}", perDay);
|
||||
double interestPerDay = interestRateInFraction * perDay;
|
||||
|
||||
todaysDate.getActualMaximum(Calendar.DATE);
|
||||
|
||||
principal = FixedDepositAccountHelper.getPrincipalAfterCompoundingInterest(todaysDate, principal, depositPeriod, interestPerDay,
|
||||
MONTHLY_INTERVAL, MONTHLY_INTERVAL);
|
||||
|
||||
LOG.info("{}", principal.toString());
|
||||
Assertions.assertTrue(Math.abs(principal - maturityAmount) < THRESHOLD, "Verifying Maturity amount for Fixed Deposit Account");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaturityAmountForMonthlyCompoundingAndMonthlyPosting_With_360_Days() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
@@ -1303,6 +1237,177 @@ public class FixedDepositTest {
|
||||
Assertions.assertTrue(Math.abs(principal - maturityAmount) < THRESHOLD, "Verifying Maturity amount for Fixed Deposit Account");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrematureClosureAmountWithPenalInterestForWholeTerm_With_360() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
|
||||
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
|
||||
DateFormat currentDateFormat = new SimpleDateFormat("dd");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -3);
|
||||
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.YEAR, 10);
|
||||
final String VALID_TO = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
|
||||
monthDayFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.MONTH, 1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(clientId);
|
||||
|
||||
final String accountingRule = NONE;
|
||||
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule);
|
||||
Assertions.assertNotNull(fixedDepositProductId);
|
||||
|
||||
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(),
|
||||
SUBMITTED_ON_DATE, WHOLE_TERM);
|
||||
Assertions.assertNotNull(fixedDepositAccountId);
|
||||
|
||||
this.fixedDepositAccountHelper.updateInterestCalculationConfigForFixedDeposit(clientId.toString(), fixedDepositProductId.toString(),
|
||||
fixedDepositAccountId.toString(), SUBMITTED_ON_DATE, VALID_FROM, VALID_TO, DAYS_360, WHOLE_TERM,
|
||||
INTEREST_CALCULATION_USING_DAILY_BALANCE, MONTHLY, MONTHLY);
|
||||
|
||||
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
|
||||
|
||||
HashMap fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
Float principal = (Float) fixedDepositAccountData.get("depositAmount");
|
||||
Integer depositPeriod = (Integer) fixedDepositAccountData.get("depositPeriod");
|
||||
HashMap daysInYearMap = (HashMap) fixedDepositAccountData.get("interestCalculationDaysInYearType");
|
||||
Float preClosurePenalInterestRate = (Float) fixedDepositAccountData.get("preClosurePenalInterest");
|
||||
Integer daysInYear = (Integer) daysInYearMap.get("id");
|
||||
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
|
||||
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
|
||||
|
||||
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositPeriod);
|
||||
interestRate -= preClosurePenalInterestRate;
|
||||
double interestRateInFraction = interestRate / 100;
|
||||
double perDay = (double) 1 / daysInYear;
|
||||
LOG.info("per day = {}", perDay);
|
||||
double interestPerDay = interestRateInFraction * perDay;
|
||||
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
|
||||
Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
|
||||
daysInMonth = daysInMonth - currentDate + 1;
|
||||
Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth);
|
||||
principal += interestPerMonth;
|
||||
todaysDate.add(Calendar.DATE, daysInMonth);
|
||||
LOG.info("{}", monthDayFormat.format(todaysDate.getTime()));
|
||||
interestPerMonth = (float) (interestPerDay * principal * currentDate);
|
||||
LOG.info("IPM = {}", interestPerMonth);
|
||||
principal += interestPerMonth;
|
||||
LOG.info("principal = {}", principal);
|
||||
|
||||
Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId);
|
||||
|
||||
this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE);
|
||||
|
||||
Integer prematureClosureTransactionId = (Integer) this.fixedDepositAccountHelper.prematureCloseForFixedDeposit(
|
||||
fixedDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_WITHDRAW_DEPOSIT, null, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
Assertions.assertNotNull(prematureClosureTransactionId);
|
||||
|
||||
fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositAccountIsPrematureClosed(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
|
||||
Float maturityAmount = (float) fixedDepositAccountData.get("maturityAmount");
|
||||
|
||||
Assertions.assertTrue(Math.abs(principal - maturityAmount) < THRESHOLD, "Verifying Pre-Closure maturity amount");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMaturityAmountForMonthlyCompoundingAndMonthlyPosting_With_365_Days() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
|
||||
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
|
||||
DateFormat currentDateFormat = new SimpleDateFormat("dd");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -3);
|
||||
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.YEAR, 10);
|
||||
final String VALID_TO = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
|
||||
todaysDate.add(Calendar.DATE, -(currentDate - 1));
|
||||
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
dateFormat.format(todaysDate.getTime());
|
||||
monthDayFormat.format(todaysDate.getTime());
|
||||
|
||||
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(clientId);
|
||||
|
||||
final String accountingRule = NONE;
|
||||
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule);
|
||||
Assertions.assertNotNull(fixedDepositProductId);
|
||||
|
||||
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(),
|
||||
SUBMITTED_ON_DATE, WHOLE_TERM);
|
||||
Assertions.assertNotNull(fixedDepositAccountId);
|
||||
|
||||
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
|
||||
|
||||
HashMap fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
Float principal = (Float) fixedDepositAccountData.get("depositAmount");
|
||||
Float maturityAmount = (Float) fixedDepositAccountData.get("maturityAmount");
|
||||
Integer depositPeriod = (Integer) fixedDepositAccountData.get("depositPeriod");
|
||||
HashMap daysInYearMap = (HashMap) fixedDepositAccountData.get("interestCalculationDaysInYearType");
|
||||
Integer daysInYear = (Integer) daysInYearMap.get("id");
|
||||
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
|
||||
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
|
||||
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositPeriod);
|
||||
double interestRateInFraction = interestRate / 100;
|
||||
double perDay = (double) 1 / daysInYear;
|
||||
LOG.info("per day = {}", perDay);
|
||||
double interestPerDay = interestRateInFraction * perDay;
|
||||
|
||||
todaysDate.getActualMaximum(Calendar.DATE);
|
||||
|
||||
principal = FixedDepositAccountHelper.getPrincipalAfterCompoundingInterest(todaysDate, principal, depositPeriod, interestPerDay,
|
||||
MONTHLY_INTERVAL, MONTHLY_INTERVAL);
|
||||
|
||||
LOG.info("{}", principal.toString());
|
||||
Assertions.assertTrue(Math.abs(principal - maturityAmount) < THRESHOLD, "Verifying Maturity amount for Fixed Deposit Account");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrematureClosureAmountWithPenalInterestForWholeTerm_With_365() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
@@ -1403,111 +1508,6 @@ public class FixedDepositTest {
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrematureClosureAmountWithPenalInterestForWholeTerm_With_360() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
this.accountHelper = new AccountHelper(this.requestSpec, this.responseSpec);
|
||||
this.savingsAccountHelper = new SavingsAccountHelper(this.requestSpec, this.responseSpec);
|
||||
this.fixedDepositAccountHelper = new FixedDepositAccountHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
DateFormat dateFormat = new SimpleDateFormat("dd MMMM yyyy", Locale.US);
|
||||
DateFormat monthDayFormat = new SimpleDateFormat("dd MMM", Locale.US);
|
||||
DateFormat currentDateFormat = new SimpleDateFormat("dd");
|
||||
|
||||
Calendar todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -3);
|
||||
final String VALID_FROM = dateFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.YEAR, 10);
|
||||
final String VALID_TO = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
todaysDate = Calendar.getInstance();
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||
final String SUBMITTED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String APPROVED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
final String ACTIVATION_DATE = dateFormat.format(todaysDate.getTime());
|
||||
monthDayFormat.format(todaysDate.getTime());
|
||||
todaysDate.add(Calendar.MONTH, 1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, 1);
|
||||
final String CLOSED_ON_DATE = dateFormat.format(todaysDate.getTime());
|
||||
|
||||
Integer clientId = ClientHelper.createClient(this.requestSpec, this.responseSpec);
|
||||
Assertions.assertNotNull(clientId);
|
||||
|
||||
final String accountingRule = NONE;
|
||||
Integer fixedDepositProductId = createFixedDepositProduct(VALID_FROM, VALID_TO, accountingRule);
|
||||
Assertions.assertNotNull(fixedDepositProductId);
|
||||
|
||||
Integer fixedDepositAccountId = applyForFixedDepositApplication(clientId.toString(), fixedDepositProductId.toString(),
|
||||
SUBMITTED_ON_DATE, WHOLE_TERM);
|
||||
Assertions.assertNotNull(fixedDepositAccountId);
|
||||
|
||||
this.fixedDepositAccountHelper.updateInterestCalculationConfigForFixedDeposit(clientId.toString(), fixedDepositProductId.toString(),
|
||||
fixedDepositAccountId.toString(), SUBMITTED_ON_DATE, VALID_FROM, VALID_TO, DAYS_360, WHOLE_TERM,
|
||||
INTEREST_CALCULATION_USING_DAILY_BALANCE, MONTHLY, MONTHLY);
|
||||
|
||||
HashMap fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsPending(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.approveFixedDeposit(fixedDepositAccountId, APPROVED_ON_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsApproved(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountStatusHashMap = this.fixedDepositAccountHelper.activateFixedDeposit(fixedDepositAccountId, ACTIVATION_DATE);
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositIsActive(fixedDepositAccountStatusHashMap);
|
||||
|
||||
HashMap fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
Float principal = (Float) fixedDepositAccountData.get("depositAmount");
|
||||
Integer depositPeriod = (Integer) fixedDepositAccountData.get("depositPeriod");
|
||||
HashMap daysInYearMap = (HashMap) fixedDepositAccountData.get("interestCalculationDaysInYearType");
|
||||
Float preClosurePenalInterestRate = (Float) fixedDepositAccountData.get("preClosurePenalInterest");
|
||||
Integer daysInYear = (Integer) daysInYearMap.get("id");
|
||||
ArrayList<ArrayList<HashMap>> interestRateChartData = FixedDepositProductHelper
|
||||
.getInterestRateChartSlabsByProductId(this.requestSpec, this.responseSpec, fixedDepositProductId);
|
||||
|
||||
Float interestRate = FixedDepositAccountHelper.getInterestRate(interestRateChartData, depositPeriod);
|
||||
interestRate -= preClosurePenalInterestRate;
|
||||
double interestRateInFraction = interestRate / 100;
|
||||
double perDay = (double) 1 / daysInYear;
|
||||
LOG.info("per day = {}", perDay);
|
||||
double interestPerDay = interestRateInFraction * perDay;
|
||||
|
||||
todaysDate.add(Calendar.MONTH, -1);
|
||||
todaysDate.add(Calendar.DAY_OF_MONTH, -1);
|
||||
Integer currentDate = Integer.valueOf(currentDateFormat.format(todaysDate.getTime()));
|
||||
Integer daysInMonth = todaysDate.getActualMaximum(Calendar.DATE);
|
||||
daysInMonth = daysInMonth - currentDate + 1;
|
||||
Float interestPerMonth = (float) (interestPerDay * principal * daysInMonth);
|
||||
principal += interestPerMonth;
|
||||
todaysDate.add(Calendar.DATE, daysInMonth);
|
||||
LOG.info("{}", monthDayFormat.format(todaysDate.getTime()));
|
||||
interestPerMonth = (float) (interestPerDay * principal * currentDate);
|
||||
LOG.info("IPM = {}", interestPerMonth);
|
||||
principal += interestPerMonth;
|
||||
LOG.info("principal = {}", principal);
|
||||
|
||||
Integer transactionIdForPostInterest = this.fixedDepositAccountHelper.postInterestForFixedDeposit(fixedDepositAccountId);
|
||||
|
||||
this.fixedDepositAccountHelper.calculatePrematureAmountForFixedDeposit(fixedDepositAccountId, CLOSED_ON_DATE);
|
||||
|
||||
Integer prematureClosureTransactionId = (Integer) this.fixedDepositAccountHelper.prematureCloseForFixedDeposit(
|
||||
fixedDepositAccountId, CLOSED_ON_DATE, CLOSURE_TYPE_WITHDRAW_DEPOSIT, null, CommonConstants.RESPONSE_RESOURCE_ID);
|
||||
Assertions.assertNotNull(prematureClosureTransactionId);
|
||||
|
||||
fixedDepositAccountStatusHashMap = FixedDepositAccountStatusChecker.getStatusOfFixedDepositAccount(this.requestSpec,
|
||||
this.responseSpec, fixedDepositAccountId.toString());
|
||||
FixedDepositAccountStatusChecker.verifyFixedDepositAccountIsPrematureClosed(fixedDepositAccountStatusHashMap);
|
||||
|
||||
fixedDepositAccountData = FixedDepositAccountHelper.getFixedDepositAccountById(this.requestSpec, this.responseSpec,
|
||||
fixedDepositAccountId);
|
||||
|
||||
Float maturityAmount = (float) fixedDepositAccountData.get("maturityAmount");
|
||||
|
||||
Assertions.assertTrue(Math.abs(principal - maturityAmount) < THRESHOLD, "Verifying Pre-Closure maturity amount");
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPrematureClosureAmountWithPenalInterestTillPrematureWithdrawal_With_365_Days() {
|
||||
this.fixedDepositProductHelper = new FixedDepositProductHelper(this.requestSpec, this.responseSpec);
|
||||
|
||||
@@ -25,6 +25,7 @@ include ':fineract-provider'
|
||||
include ':fineract-war'
|
||||
include ':integration-tests'
|
||||
include ':twofactor-tests'
|
||||
include ':instancemode-tests'
|
||||
include ':oauth2-tests'
|
||||
include ':fineract-client'
|
||||
include ':fineract-doc'
|
||||
|
||||
Reference in New Issue
Block a user