diff --git a/api-docs/apiLive.htm b/api-docs/apiLive.htm
index 11e6ee558..d8efbfadf 100644
--- a/api-docs/apiLive.htm
+++ b/api-docs/apiLive.htm
@@ -1846,11 +1846,17 @@
| User Generated Documents |
@@ -13737,6 +13743,31 @@ Request Body:
Allow transactions on non-working days is configurable by enabling/disbaling the allow-transactions-on-non_workingday parameter in Global configurations.
+
+
+ Mandotory Field Descriptions |
+
+
+ | recurrence |
+
+
+ | Recurrence pattern |
+
+
+ | repaymentRescheduleType |
+
+
+ | repayment reschedule type .Options listed on the schedule for repayments on non-working days
+ |
+
+
+ | locale |
+
+
+ | locale must be provided. |
+
+
+
Schedule for repayments on non-working day |
@@ -13772,6 +13803,111 @@ Request Body:
+
+
+
+
Working Days Template
+
This is a convenience resource. It can be useful when
+ building maintenance user interface screens for working days.
+
+
Example Request:
+
workingdays/template
+
+
+
+GET https://DomainName/api/v1/workingdays/template
+
+
+{
+ "repaymentRescheduleOptions": [
+ {
+ "id": 1,
+ "code": "RepaymentRescheduleType.same.day",
+ "value": "same day"
+ },
+ {
+ "id": 4,
+ "code": "RepaymentRescheduleType.move.to.previous.working.day",
+ "value": "move to previous working day"
+ },
+ {
+ "id": 3,
+ "code": "RepaymentRescheduleType.move.to.next.repayment.meeting.day",
+ "value": "move to next repayment meeting day"
+ },
+ {
+ "id": 2,
+ "code": "RepaymentRescheduleType.move.to.next.working.day",
+ "value": "move to next working day"
+ }
+ ]
+}
+
+
+
+
+
+
+
List Working days
+
Example Requests:
+
workingdays
+
+
+
+
+
+GET https://DomainName/api/v1/workingdays
+
+
+[
+ {
+ "id": 1,
+ "recurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,FR",
+ "repaymentRescheduleType": {
+ "id": 4,
+ "code": "RepaymentRescheduleType.move.to.next.working.day",
+ "value": "move to next working day"
+ }
+ }
+]
+
+
+
+
+
+
+
Update a Working Day
+
+
+ Mandatory Fields |
+
+
+ | recurrence,repaymentRescheduleType,locale |
+
+
+
+
+
+PUT https://DomainName/api/v1/Workingdays/1
+
+
+PUT holidays
+Content-Type: application/json
+Request Body:
+{
+"recurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,SU",
+"locale": "en",
+"repaymentsRescheduledType": 4
+}
+
+
+{
+"resourceId": 1
+}
+
+
+
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java
old mode 100644
new mode 100755
index 4d44c925f..fc1d3dde2
--- a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/ConcurrencyIntegrationTest.java
@@ -1,3 +1,8 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
package org.mifosplatform.integrationtests;
import java.text.DateFormat;
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/WorkingDaysTest.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/WorkingDaysTest.java
new file mode 100755
index 000000000..f5fa117f8
--- /dev/null
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/WorkingDaysTest.java
@@ -0,0 +1,55 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.integrationtests;
+
+import com.jayway.restassured.builder.RequestSpecBuilder;
+import com.jayway.restassured.builder.ResponseSpecBuilder;
+import com.jayway.restassured.http.ContentType;
+import com.jayway.restassured.specification.RequestSpecification;
+import com.jayway.restassured.specification.ResponseSpecification;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.mifosplatform.integrationtests.common.CommonConstants;
+import org.mifosplatform.integrationtests.common.Utils;
+import org.mifosplatform.integrationtests.common.WorkingDaysHelper;
+
+import java.util.HashMap;
+import java.util.List;
+
+import static org.junit.Assert.assertEquals;
+
+@SuppressWarnings({ "rawtypes", "unchecked" })
+public class WorkingDaysTest {
+
+ private ResponseSpecification responseSpec;
+ private RequestSpecification requestSpec;
+ private ResponseSpecification generalResponseSpec;
+
+ @Before
+ public void setUp(){
+ Utils.initializeRESTAssured();
+ this.requestSpec = new RequestSpecBuilder().setContentType(ContentType.JSON).build();
+ this.requestSpec.header("Authorization", "Basic " + Utils.loginIntoServerAndGetBase64EncodedAuthenticationKey());
+ this.responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
+ this.generalResponseSpec = new ResponseSpecBuilder().build();
+
+ }
+
+ @Test
+ public void updateWorkingDays(){
+ HashMap response = (HashMap)WorkingDaysHelper.updateWorkingDays(requestSpec, responseSpec);
+ Assert.assertNotNull(response.get("resourceId"));
+ }
+
+ @Test
+ public void updateWorkingDaysWithWrongRecurrencePattern(){
+ final List error = (List) WorkingDaysHelper.updateWorkingDaysWithWrongRecurrence(requestSpec, generalResponseSpec, CommonConstants.RESPONSE_ERROR);
+ assertEquals("Verify wrong recurrence pattern error", "error.msg.recurring.rule.parsing.error", error.get(0).get("userMessageGlobalisationCode"));
+ }
+
+
+}
diff --git a/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/WorkingDaysHelper.java b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/WorkingDaysHelper.java
new file mode 100755
index 000000000..92115506f
--- /dev/null
+++ b/mifosng-provider/src/integrationTest/java/org/mifosplatform/integrationtests/common/WorkingDaysHelper.java
@@ -0,0 +1,78 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.integrationtests.common;
+
+
+import com.google.gson.Gson;
+import com.jayway.restassured.specification.RequestSpecification;
+import com.jayway.restassured.specification.ResponseSpecification;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Random;
+
+public class WorkingDaysHelper {
+ private static final String WORKINGDAYS_URL = "/mifosng-provider/api/v1/workingdays";
+ private static final String CREATE_HOLIDAY_URL = WORKINGDAYS_URL + "?" + Utils.TENANT_IDENTIFIER;
+
+
+ public static Object updateWorkingDays(final RequestSpecification requestSpec, final ResponseSpecification responseSpec) {
+ final String UPDATE_WORKINGDAYS_URL = WORKINGDAYS_URL +"/" +workingDaysId(requestSpec,responseSpec) + "?" + Utils.TENANT_IDENTIFIER;
+ System.out.println("---------------------------------UPDATE WORKINGDAY---------------------------------------------");
+ return Utils.performServerPut(requestSpec, responseSpec,UPDATE_WORKINGDAYS_URL, updateWorkingDaysAsJson(), "");
+ }
+
+
+ public static Object updateWorkingDaysWithWrongRecurrence(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,String jsonAttributeToGetback){
+ final String UPDATE_WORKINGDAYS_URL = WORKINGDAYS_URL +"/" +workingDaysId(requestSpec,responseSpec) + "?" + Utils.TENANT_IDENTIFIER;
+ System.out.println("---------------------------------UPDATE WORKINGDAY WITH WRONG RECURRENCE-----------------------------------------");
+ return Utils.performServerPut(requestSpec, responseSpec,UPDATE_WORKINGDAYS_URL, updateWorkingDayWithWrongRecur(), jsonAttributeToGetback);
+ }
+
+
+ public static String updateWorkingDaysAsJson(){
+ final HashMap map = new HashMap<>();
+ map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH");
+ map.put("locale", "en");
+ map.put("repaymentRescheduleType", randomInt(1,4));
+ System.out.println("map : " + map);
+ return new Gson().toJson(map);
+ }
+
+
+ public static String updateWorkingDayWithWrongRecur(){
+ final HashMap map = new HashMap<>();
+ map.put("recurrence", "FREQ=WEEKLY;INTERVAL=1;BYDAY=MP,TI,TE,TH");
+ map.put("locale", "en");
+ map.put("repaymentRescheduleType", randomInt(1,4));
+ System.out.println("map : " + map);
+ return new Gson().toJson(map);
+ }
+
+
+ public static int randomInt(int low, int high){
+ int i = new Random().nextInt(high) + low;
+ return i;
+ }
+
+ public static int workingDaysId(final RequestSpecification requestSpec,final ResponseSpecification responseSpec){
+ List> workingDaysId = getAllWorkingDays(requestSpec,responseSpec);
+ final HashMap workingDay = workingDaysId.get(0);
+ return (int) workingDay.get("id");
+ }
+
+
+ public static ArrayList> getAllWorkingDays(
+ final RequestSpecification requestSpec,
+ final ResponseSpecification responseSpec) {
+
+ return Utils.performServerGet(requestSpec, responseSpec, WORKINGDAYS_URL + "?"
+ + Utils.TENANT_IDENTIFIER, "");
+
+ }
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
index f088e3488..af213f405 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/domain/CommandWrapper.java
@@ -1012,8 +1012,13 @@ public class CommandWrapper {
public boolean isEnableOperation() {
return this.actionName.equalsIgnoreCase("ENABLE");
}
-
+
public boolean isEntityMappingResource() {
return this.entityName.equalsIgnoreCase("ENTITYMAPPING");
}
+
+ public boolean isWorkingDaysResource() {
+ return this.entityName.equalsIgnoreCase("WORKINGDAYS");
+ }
+
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
index 987e2cb57..43a6bf67f 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/CommandWrapperBuilder.java
@@ -2353,4 +2353,12 @@ public class CommandWrapperBuilder {
this.href = "/entitytoentitymapping/" + mapId;
return this;
}
+ public CommandWrapperBuilder updateWorkingDays(final Long workingDaysId) {
+ this.actionName = "UPDATE";
+ this.entityName = "WORKINGDAYS";
+ this.entityId = workingDaysId;
+ this.href = "/workingdays/" + workingDaysId;
+ return this;
+ }
+
}
\ No newline at end of file
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
index a891ed8bd..a094c43b0 100755
--- a/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
+++ b/mifosng-provider/src/main/java/org/mifosplatform/commands/service/SynchronousCommandProcessingService.java
@@ -923,6 +923,12 @@ public class SynchronousCommandProcessingService implements CommandProcessingSer
} else {
throw new UnsupportedCommandException(wrapper.commandName());
}
+ } else if(wrapper.isWorkingDaysResource()) {
+ if(wrapper.isUpdate()){
+ handler = this.applicationContext.getBean("updateWorkingDaysCommandHandler",NewCommandSourceHandler.class);
+ }else {
+ throw new UnsupportedCommandException(wrapper.commandName());
+ }
} else {
throw new UnsupportedCommandException(wrapper.commandName());
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiConstants.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiConstants.java
new file mode 100755
index 000000000..f18164bac
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiConstants.java
@@ -0,0 +1,36 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.organisation.workingdays.api;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+public class WorkingDaysApiConstants {
+
+ public static final String WORKING_DAYS_RESOURCE_NAME = "workingdays";
+
+ // request parameters
+ public static final String recurrence = "recurrence";
+
+ public static final String repayment_rescheduling_enum = "repaymentRescheduleType";
+
+ public static final String idParamName = "id";
+
+ public static final String rescheduleRepaymentTemplate = "rescheduleRepaymentTemplate";
+ public static final String localeParamName = "locale";
+
+
+
+ public static final Set WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS =new HashSet<>(Arrays.asList(
+ recurrence,repayment_rescheduling_enum,localeParamName
+ ));
+ public static final Set WORKING_DAYS_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
+ recurrence,repayment_rescheduling_enum
+ ));
+
+ public static final Set WORKING_DAYS_TEMPLATE_PARAMETERS = new HashSet<>(Arrays.asList(rescheduleRepaymentTemplate));
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiResource.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiResource.java
new file mode 100755
index 000000000..e2557dde4
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/api/WorkingDaysApiResource.java
@@ -0,0 +1,109 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.organisation.workingdays.api;
+
+import org.mifosplatform.commands.domain.CommandWrapper;
+import org.mifosplatform.commands.service.CommandWrapperBuilder;
+import org.mifosplatform.commands.service.PortfolioCommandSourceWritePlatformService;
+import org.mifosplatform.infrastructure.core.api.ApiRequestParameterHelper;
+import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
+import org.mifosplatform.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
+import org.mifosplatform.infrastructure.core.serialization.DefaultToApiJsonSerializer;
+import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
+import org.mifosplatform.organisation.workingdays.data.WorkingDaysData;
+import org.mifosplatform.organisation.workingdays.service.WorkingDaysReadPlatformService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Scope;
+import org.springframework.stereotype.Component;
+
+import javax.ws.rs.*;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.UriInfo;
+import java.util.Collection;
+
+@Path("/workingdays")
+@Component
+@Scope("singleton")
+public class WorkingDaysApiResource {
+
+
+ private final DefaultToApiJsonSerializer toApiJsonSerializer;
+ private final WorkingDaysReadPlatformService workingDaysReadPlatformService;
+ private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
+ private final PlatformSecurityContext context;
+ private final ApiRequestParameterHelper apiRequestParameterHelper;
+
+
+ @Autowired
+ public WorkingDaysApiResource(DefaultToApiJsonSerializer toApiJsonSerializer, WorkingDaysReadPlatformService workingDaysReadPlatformService, PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService, PlatformSecurityContext context, ApiRequestParameterHelper apiRequestParameterHelper) {
+ this.toApiJsonSerializer = toApiJsonSerializer;
+ this.workingDaysReadPlatformService = workingDaysReadPlatformService;
+ this.commandsSourceWritePlatformService = commandsSourceWritePlatformService;
+ this.context = context;
+ this.apiRequestParameterHelper = apiRequestParameterHelper;
+ }
+
+
+
+
+ @GET
+ @Path("{workingdaysId}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public String retrieveOne(@PathParam("workingdaysId") final Long workingDaysId, @Context final UriInfo uriInfo){
+ this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
+
+ final WorkingDaysData workingDaysData = this.workingDaysReadPlatformService.retrieveOne(workingDaysId);
+
+ final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ return this.toApiJsonSerializer.serialize(settings,workingDaysData);
+ }
+
+ @GET
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public String retrieveAll(@Context final UriInfo uriInfo){
+ this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
+ final Collection workingDaysData = this.workingDaysReadPlatformService.retrieveAll();
+
+ final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ return this.toApiJsonSerializer.serialize(settings,workingDaysData);
+ }
+
+
+
+ @PUT
+ @Path("{workingdaysId}")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public String update(@PathParam("workingdaysId") final Long workingDaysId,final String jsonRequestBody, @Context final UriInfo uriInfo){
+ this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
+
+ final CommandWrapper commandRequest = new CommandWrapperBuilder().updateWorkingDays(workingDaysId).withJson(jsonRequestBody).build();
+
+ final CommandProcessingResult result = this.commandsSourceWritePlatformService.logCommandSource(commandRequest);
+
+ return this.toApiJsonSerializer.serialize(result);
+ }
+
+
+ @GET
+ @Path("/template")
+ @Consumes({ MediaType.APPLICATION_JSON })
+ @Produces({ MediaType.APPLICATION_JSON })
+ public String template(@Context final UriInfo uriInfo){
+ this.context.authenticatedUser().validateHasReadPermission(WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
+
+ final WorkingDaysData repaymentRescheduleOptions = this.workingDaysReadPlatformService.repaymentRescheduleType();
+
+ final ApiRequestJsonSerializationSettings settings = this.apiRequestParameterHelper.process(uriInfo.getQueryParameters());
+ return this.toApiJsonSerializer.serialize(settings,repaymentRescheduleOptions,WorkingDaysApiConstants.WORKING_DAYS_TEMPLATE_PARAMETERS);
+ }
+
+
+
+}
diff --git a/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/data/WorkingDayValidator.java b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/data/WorkingDayValidator.java
new file mode 100755
index 000000000..1f0d2868b
--- /dev/null
+++ b/mifosng-provider/src/main/java/org/mifosplatform/organisation/workingdays/data/WorkingDayValidator.java
@@ -0,0 +1,70 @@
+/**
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+package org.mifosplatform.organisation.workingdays.data;
+
+import com.google.gson.JsonElement;
+import com.google.gson.reflect.TypeToken;
+
+import org.apache.commons.lang.StringUtils;
+import org.mifosplatform.infrastructure.core.data.ApiParameterError;
+import org.mifosplatform.infrastructure.core.data.DataValidatorBuilder;
+import org.mifosplatform.infrastructure.core.exception.InvalidJsonException;
+import org.mifosplatform.infrastructure.core.exception.PlatformApiDataValidationException;
+import org.mifosplatform.infrastructure.core.serialization.FromJsonHelper;
+import org.mifosplatform.organisation.workingdays.api.WorkingDaysApiConstants;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.Type;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Component
+public class WorkingDayValidator {
+
+ private final FromJsonHelper fromApiJsonHelper;
+
+ @Autowired
+ public WorkingDayValidator(FromJsonHelper fromApiJsonHelper) {
+ this.fromApiJsonHelper = fromApiJsonHelper;
+ }
+
+
+ public void validateForUpdate(final String json){
+ if (StringUtils.isBlank(json)) { throw new InvalidJsonException(); }
+
+ final Type typeOfMap = new TypeToken