MIFOSX-1877 ability to edit working days by clients and added license text to ConcurrencyIntegrationTest file
This commit is contained in:
+137
-1
@@ -1846,11 +1846,17 @@
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#workingdays">Working days</a></td>
|
||||
<td>workingdays</td>
|
||||
<td><a href="#workingdays_list">List workingdays</a></td>
|
||||
<td><a href="#workingdays_template">Working days template</a></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td></td>
|
||||
<td>workingdays/{workingdaysId}</td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
<td><a href="#workingdays_update">Update a workingdays</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><a href="#templates">User Generated Documents</a></td>
|
||||
@@ -13737,6 +13743,31 @@ Request Body:
|
||||
<p>
|
||||
Allow transactions on non-working days is configurable by enabling/disbaling the allow-transactions-on-non_workingday parameter in <a href="#configs_global">Global configurations</a>.
|
||||
</p>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Mandotory Field Descriptions</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recurrence</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>Recurrence pattern</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>repaymentRescheduleType</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>repayment reschedule type .Options listed on the schedule for repayments on non-working days
|
||||
</td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>locale</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class=fielddesc>locale must be provided.</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
<table id="nw_repayment_schedule_rule" class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Schedule for repayments on non-working day</div></td>
|
||||
@@ -13772,6 +13803,111 @@ Request Body:
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<a id="workingdays_template" name="workingdays_template"
|
||||
class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Working Days Template</h4>
|
||||
<p>This is a convenience resource. It can be useful when
|
||||
building maintenance user interface screens for working days.
|
||||
</p>
|
||||
<p>Example Request:</p>
|
||||
<div class=apiClick>workingdays/template</div>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/workingdays/template
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"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"
|
||||
}
|
||||
]
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<a id="workingdays_list" name="workingdays_list" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>List Working days</h4>
|
||||
<p>Example Requests:</p>
|
||||
<div class=apiClick>workingdays</div>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
GET https://DomainName/api/v1/workingdays
|
||||
</code>
|
||||
<code class="method-response">
|
||||
[
|
||||
{
|
||||
"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"
|
||||
}
|
||||
}
|
||||
]
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
<a id="workingdays_update" name="workingdays_update" class="old-syle-anchor"> </a>
|
||||
<div class="method-section">
|
||||
<div class="method-description">
|
||||
<h4>Update a Working Day</h4>
|
||||
<table class=matrixHeading>
|
||||
<tr class="matrixHeadingBG">
|
||||
<td><div class="mifosXHeading2">Mandatory Fields</div></td>
|
||||
</tr>
|
||||
<tr class=alt>
|
||||
<td>recurrence,repaymentRescheduleType,locale</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="method-example">
|
||||
<code class="method-declaration">
|
||||
PUT https://DomainName/api/v1/Workingdays/1
|
||||
</code>
|
||||
<code class="method-request">
|
||||
PUT holidays
|
||||
Content-Type: application/json
|
||||
Request Body:
|
||||
{
|
||||
"recurrence": "FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU,WE,TH,SU",
|
||||
"locale": "en",
|
||||
"repaymentsRescheduledType": 4
|
||||
}
|
||||
</code>
|
||||
<code class="method-response">
|
||||
{
|
||||
"resourceId": 1
|
||||
}
|
||||
</code>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- end of workingdays api docs -->
|
||||
|
||||
|
||||
Regular → Executable
+5
@@ -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;
|
||||
|
||||
Executable
+55
@@ -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<HashMap> 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"));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+78
@@ -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<String, Object> 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<String, Object> 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<HashMap<String, Object>> workingDaysId = getAllWorkingDays(requestSpec,responseSpec);
|
||||
final HashMap<String, Object> workingDay = workingDaysId.get(0);
|
||||
return (int) workingDay.get("id");
|
||||
}
|
||||
|
||||
|
||||
public static ArrayList<HashMap<String, Object>> getAllWorkingDays(
|
||||
final RequestSpecification requestSpec,
|
||||
final ResponseSpecification responseSpec) {
|
||||
|
||||
return Utils.performServerGet(requestSpec, responseSpec, WORKINGDAYS_URL + "?"
|
||||
+ Utils.TENANT_IDENTIFIER, "");
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+6
-1
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
+8
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
+6
@@ -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());
|
||||
|
||||
+36
@@ -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<String> WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS =new HashSet<>(Arrays.asList(
|
||||
recurrence,repayment_rescheduling_enum,localeParamName
|
||||
));
|
||||
public static final Set<String> WORKING_DAYS_RESPONSE_DATA_PARAMETERS = new HashSet<>(Arrays.asList(idParamName,
|
||||
recurrence,repayment_rescheduling_enum
|
||||
));
|
||||
|
||||
public static final Set<String> WORKING_DAYS_TEMPLATE_PARAMETERS = new HashSet<>(Arrays.asList(rescheduleRepaymentTemplate));
|
||||
}
|
||||
+109
@@ -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<WorkingDaysData> toApiJsonSerializer;
|
||||
private final WorkingDaysReadPlatformService workingDaysReadPlatformService;
|
||||
private final PortfolioCommandSourceWritePlatformService commandsSourceWritePlatformService;
|
||||
private final PlatformSecurityContext context;
|
||||
private final ApiRequestParameterHelper apiRequestParameterHelper;
|
||||
|
||||
|
||||
@Autowired
|
||||
public WorkingDaysApiResource(DefaultToApiJsonSerializer<WorkingDaysData> 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> 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);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
+70
@@ -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<Map<String, Object>>() {}.getType();
|
||||
this.fromApiJsonHelper.checkForUnsupportedParameters(typeOfMap, json,
|
||||
WorkingDaysApiConstants.WORKING_DAYS_CREATE_OR_UPDATE_REQUEST_DATA_PARAMETERS);
|
||||
final JsonElement element = this.fromApiJsonHelper.parse(json);
|
||||
|
||||
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
|
||||
|
||||
|
||||
final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors)
|
||||
.resource( WorkingDaysApiConstants.WORKING_DAYS_RESOURCE_NAME);
|
||||
|
||||
final String recurrence = this.fromApiJsonHelper.extractStringNamed(WorkingDaysApiConstants.recurrence, element);
|
||||
baseDataValidator.reset().parameter(WorkingDaysApiConstants.recurrence).value(recurrence).notNull();
|
||||
|
||||
final Integer repaymentRescheduleType = this.fromApiJsonHelper.extractIntegerSansLocaleNamed("repaymentRescheduleType", element);
|
||||
baseDataValidator.reset().parameter("repaymentRescheduleType").value(repaymentRescheduleType).ignoreIfNull().inMinMaxRange(1,4);
|
||||
|
||||
|
||||
|
||||
throwExceptionIfValidationWarningsExist(dataValidationErrors);
|
||||
|
||||
}
|
||||
|
||||
|
||||
private void throwExceptionIfValidationWarningsExist(final List<ApiParameterError> dataValidationErrors) {
|
||||
if (!dataValidationErrors.isEmpty()) {
|
||||
//
|
||||
throw new PlatformApiDataValidationException(dataValidationErrors);
|
||||
}
|
||||
}
|
||||
}
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
/**
|
||||
* 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 org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public class WorkingDaysData {
|
||||
@SuppressWarnings("unused")
|
||||
private final Long id;
|
||||
@SuppressWarnings("unused")
|
||||
private final String recurrence;
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
private final EnumOptionData repaymentRescheduleType;
|
||||
|
||||
//template date
|
||||
private final Collection<EnumOptionData> repaymentRescheduleOptions;
|
||||
|
||||
|
||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType) {
|
||||
this.id = id;
|
||||
this.recurrence = recurrence;
|
||||
this.repaymentRescheduleType = repaymentRescheduleType;
|
||||
this.repaymentRescheduleOptions = null;
|
||||
}
|
||||
|
||||
public WorkingDaysData(Long id, String recurrence, EnumOptionData repaymentRescheduleType, Collection<EnumOptionData> repaymentRescheduleOptions) {
|
||||
this.id = null;
|
||||
this.recurrence = null;
|
||||
this.repaymentRescheduleType = null;
|
||||
this.repaymentRescheduleOptions = repaymentRescheduleOptions;
|
||||
}
|
||||
}
|
||||
Regular → Executable
+25
-2
@@ -6,11 +6,14 @@
|
||||
|
||||
package org.mifosplatform.organisation.workingdays.domain;
|
||||
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import org.springframework.data.jpa.domain.AbstractPersistable;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@Entity
|
||||
@Table(name = "m_working_days")
|
||||
@@ -45,4 +48,24 @@ public class WorkingDays extends AbstractPersistable<Long> {
|
||||
return this.repaymentReschedulingType;
|
||||
}
|
||||
|
||||
|
||||
public Map<String, Object> update(final JsonCommand command) {
|
||||
final Map<String, Object> actualChanges = new LinkedHashMap<>(7);
|
||||
|
||||
final String recurrenceParamName = "recurrence";
|
||||
if (command.isChangeInStringParameterNamed(recurrenceParamName, this.recurrence)) {
|
||||
final String newValue = command.stringValueOfParameterNamed(recurrenceParamName);
|
||||
actualChanges.put(recurrenceParamName, newValue);
|
||||
this.recurrence = newValue;
|
||||
}
|
||||
|
||||
final String repaymentRescheduleTypeParamName = "repaymentRescheduleType";
|
||||
if (command.isChangeInIntegerParameterNamed(repaymentRescheduleTypeParamName, this.repaymentReschedulingType)) {
|
||||
final Integer newValue =command.integerValueOfParameterNamed(repaymentRescheduleTypeParamName);
|
||||
actualChanges.put(repaymentRescheduleTypeParamName, WorkingDaysEnumerations.workingDaysStatusType(newValue));
|
||||
this.repaymentReschedulingType = RepaymentRescheduleType.fromInt(newValue).getValue();
|
||||
}
|
||||
return actualChanges;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* 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.domain;
|
||||
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
|
||||
public class WorkingDaysEnumerations {
|
||||
|
||||
public static EnumOptionData workingDaysStatusType(final int id) {
|
||||
return repaymentRescheduleType(RepaymentRescheduleType.fromInt(id));
|
||||
}
|
||||
|
||||
public static EnumOptionData repaymentRescheduleType(final RepaymentRescheduleType type){
|
||||
EnumOptionData optionData = null;
|
||||
switch(type){
|
||||
case INVALID:
|
||||
optionData = new EnumOptionData(RepaymentRescheduleType.INVALID.getValue().longValue(),RepaymentRescheduleType.INVALID.getCode(),
|
||||
"invalid");
|
||||
break;
|
||||
|
||||
case SAME_DAY:
|
||||
optionData = new EnumOptionData(RepaymentRescheduleType.SAME_DAY.getValue().longValue(),RepaymentRescheduleType.SAME_DAY.getCode(),
|
||||
"same day");
|
||||
|
||||
break;
|
||||
case MOVE_TO_NEXT_WORKING_DAY:
|
||||
optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getValue().longValue(),RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY.getCode(),
|
||||
"move to next working day");
|
||||
break;
|
||||
|
||||
case MOVE_TO_NEXT_REPAYMENT_MEETING_DAY:
|
||||
optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY.getValue().longValue(),RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY.getCode(),
|
||||
"move to next repayment meeting day");
|
||||
break;
|
||||
case MOVE_TO_PREVIOUS_WORKING_DAY:
|
||||
optionData = new EnumOptionData(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY.getValue().longValue(),RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY.getCode(),
|
||||
"move to previous working day");
|
||||
break;
|
||||
}
|
||||
|
||||
return optionData;
|
||||
}
|
||||
}
|
||||
Regular → Executable
+4
@@ -15,4 +15,8 @@ public class WorkingDaysNotFoundException extends AbstractPlatformResourceNotFou
|
||||
public WorkingDaysNotFoundException() {
|
||||
super("error.msg.working.days.not.configured", "Must configure the Working days for the organisation.");
|
||||
}
|
||||
|
||||
public WorkingDaysNotFoundException(Long id){
|
||||
super("error.msg.workingdays.id.invalid", "Working day with identifier " + id + " does not exist", id);
|
||||
}
|
||||
}
|
||||
+31
@@ -0,0 +1,31 @@
|
||||
/**
|
||||
* 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.handler;
|
||||
|
||||
|
||||
import org.mifosplatform.commands.handler.NewCommandSourceHandler;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.organisation.workingdays.service.WorkingDaysWritePlatformService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@Service
|
||||
public class UpdateWorkingDaysCommandHandler implements NewCommandSourceHandler {
|
||||
|
||||
private final WorkingDaysWritePlatformService workingDaysWritePlatformService;
|
||||
|
||||
@Autowired
|
||||
public UpdateWorkingDaysCommandHandler(final WorkingDaysWritePlatformService workingDaysWritePlatformService) {
|
||||
this.workingDaysWritePlatformService = workingDaysWritePlatformService;
|
||||
}
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult processCommand(JsonCommand command) {
|
||||
return this.workingDaysWritePlatformService.updateWorkingDays(command);
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
|
||||
import org.mifosplatform.organisation.workingdays.data.WorkingDaysData;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface WorkingDaysReadPlatformService {
|
||||
|
||||
Collection<WorkingDaysData> retrieveAll();
|
||||
WorkingDaysData retrieveOne(Long id);
|
||||
|
||||
WorkingDaysData repaymentRescheduleType();
|
||||
}
|
||||
+96
@@ -0,0 +1,96 @@
|
||||
/**
|
||||
* 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.service;
|
||||
|
||||
|
||||
import org.mifosplatform.infrastructure.core.data.EnumOptionData;
|
||||
import org.mifosplatform.infrastructure.core.domain.JdbcSupport;
|
||||
import org.mifosplatform.infrastructure.core.service.RoutingDataSource;
|
||||
import org.mifosplatform.infrastructure.security.service.PlatformSecurityContext;
|
||||
import org.mifosplatform.organisation.workingdays.data.WorkingDaysData;
|
||||
import org.mifosplatform.organisation.workingdays.domain.RepaymentRescheduleType;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysEnumerations;
|
||||
import org.mifosplatform.organisation.workingdays.exception.WorkingDaysNotFoundException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.dao.EmptyResultDataAccessException;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.jdbc.core.RowMapper;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
|
||||
@Service
|
||||
public class WorkingDaysReadPlatformServiceImpl implements WorkingDaysReadPlatformService{
|
||||
|
||||
private final PlatformSecurityContext context;
|
||||
private final JdbcTemplate jdbcTemplate;
|
||||
|
||||
@Autowired
|
||||
public WorkingDaysReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) {
|
||||
this.context = context;
|
||||
this.jdbcTemplate = new JdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
|
||||
private static final class WorkingDaysMapper implements RowMapper<WorkingDaysData> {
|
||||
|
||||
private final String schema;
|
||||
|
||||
public WorkingDaysMapper() {
|
||||
final StringBuilder sqlBuilder = new StringBuilder(100);
|
||||
sqlBuilder.append("w.id as id,w.recurrence as recurrence,w.repayment_rescheduling_enum as status_enum ");
|
||||
sqlBuilder.append("from m_working_days w");
|
||||
|
||||
this.schema = sqlBuilder.toString();
|
||||
}
|
||||
public String schema() {
|
||||
return this.schema;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkingDaysData mapRow(ResultSet rs, int rowNum) throws SQLException {
|
||||
final Long id = rs.getLong("id");
|
||||
final String recurrence = rs.getString("recurrence");
|
||||
final Integer statusEnum = JdbcSupport.getInteger(rs, "status_enum");
|
||||
final EnumOptionData status = WorkingDaysEnumerations.workingDaysStatusType(statusEnum);
|
||||
|
||||
return new WorkingDaysData(id,recurrence,status);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<WorkingDaysData> retrieveAll() {
|
||||
final WorkingDaysMapper rm = new WorkingDaysMapper();
|
||||
final String sql = " select " + rm.schema() ;
|
||||
return this.jdbcTemplate.query(sql, rm, new Object[] {});
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkingDaysData retrieveOne(final Long id) {
|
||||
try {
|
||||
final WorkingDaysMapper rm = new WorkingDaysMapper();
|
||||
|
||||
final String sql = " select " + rm.schema() + " where w.id = ?";
|
||||
|
||||
return this.jdbcTemplate.queryForObject(sql, rm, new Object[] { id });
|
||||
} catch (final EmptyResultDataAccessException e) {
|
||||
throw new WorkingDaysNotFoundException(id);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public WorkingDaysData repaymentRescheduleType() {
|
||||
Collection<EnumOptionData> repaymentRescheduleOptions = Arrays.asList(WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.SAME_DAY),
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_WORKING_DAY),
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_NEXT_REPAYMENT_MEETING_DAY),
|
||||
WorkingDaysEnumerations.repaymentRescheduleType(RepaymentRescheduleType.MOVE_TO_PREVIOUS_WORKING_DAY)
|
||||
);
|
||||
return new WorkingDaysData(null,null,null,repaymentRescheduleOptions);
|
||||
}
|
||||
}
|
||||
Regular → Executable
+4
@@ -6,10 +6,14 @@
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
|
||||
public interface WorkingDaysWritePlatformService {
|
||||
|
||||
boolean isWorkingDay(LocalDate transactionDate);
|
||||
|
||||
boolean isTransactionAllowedOnNonWorkingDay();
|
||||
|
||||
CommandProcessingResult updateWorkingDays(JsonCommand command);
|
||||
}
|
||||
|
||||
Regular → Executable
+42
-1
@@ -5,24 +5,39 @@
|
||||
*/
|
||||
package org.mifosplatform.organisation.workingdays.service;
|
||||
|
||||
import net.fortuna.ical4j.model.ValidationException;
|
||||
import net.fortuna.ical4j.model.property.RRule;
|
||||
import org.joda.time.LocalDate;
|
||||
import org.mifosplatform.infrastructure.configuration.domain.ConfigurationDomainService;
|
||||
import org.mifosplatform.infrastructure.core.api.JsonCommand;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResult;
|
||||
import org.mifosplatform.infrastructure.core.data.CommandProcessingResultBuilder;
|
||||
import org.mifosplatform.infrastructure.core.exception.PlatformDataIntegrityException;
|
||||
import org.mifosplatform.organisation.workingdays.api.WorkingDaysApiConstants;
|
||||
import org.mifosplatform.organisation.workingdays.data.WorkingDayValidator;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDays;
|
||||
import org.mifosplatform.organisation.workingdays.domain.WorkingDaysRepositoryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.Map;
|
||||
|
||||
@Service
|
||||
public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements WorkingDaysWritePlatformService {
|
||||
|
||||
private final WorkingDaysRepositoryWrapper daysRepositoryWrapper;
|
||||
private final ConfigurationDomainService configurationDomainService;
|
||||
private final WorkingDayValidator fromApiJsonDeserializer;
|
||||
|
||||
@Autowired
|
||||
public WorkingDaysWritePlatformServiceJpaRepositoryImpl(final WorkingDaysRepositoryWrapper daysRepositoryWrapper,
|
||||
final ConfigurationDomainService configurationDomainService) {
|
||||
final ConfigurationDomainService configurationDomainService,
|
||||
final WorkingDayValidator fromApiJsonDeserializer) {
|
||||
this.daysRepositoryWrapper = daysRepositoryWrapper;
|
||||
this.configurationDomainService = configurationDomainService;
|
||||
this.fromApiJsonDeserializer = fromApiJsonDeserializer;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -36,4 +51,30 @@ public class WorkingDaysWritePlatformServiceJpaRepositoryImpl implements Working
|
||||
return this.configurationDomainService.allowTransactionsOnNonWorkingDayEnabled();
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Override
|
||||
public CommandProcessingResult updateWorkingDays(JsonCommand command) {
|
||||
String recurrence = "";
|
||||
RRule rrule = null;
|
||||
try{
|
||||
this.fromApiJsonDeserializer.validateForUpdate(command.json());
|
||||
final WorkingDays workingDays = this.daysRepositoryWrapper.findOne();
|
||||
|
||||
recurrence = command.stringValueOfParameterNamed(WorkingDaysApiConstants.recurrence);
|
||||
rrule = new RRule(recurrence);
|
||||
rrule.validate();
|
||||
|
||||
Map<String, Object> changes = workingDays.update(command);
|
||||
this.daysRepositoryWrapper.saveAndFlush(workingDays);
|
||||
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).withEntityId(workingDays.getId()).build();
|
||||
}catch (final ValidationException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.invalid.recurring.rule", "The Recurring Rule value: " + recurrence
|
||||
+ " is not valid.", "recurrence", recurrence);
|
||||
} catch (final IllegalArgumentException|ParseException e) {
|
||||
throw new PlatformDataIntegrityException("error.msg.recurring.rule.parsing.error",
|
||||
"Error in passing the Recurring Rule value: " + recurrence, "recurrence", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
INSERT INTO `m_permission` (
|
||||
`grouping` ,
|
||||
`code` ,
|
||||
`entity_name` ,
|
||||
`action_name` ,
|
||||
`can_maker_checker`
|
||||
)
|
||||
VALUES (
|
||||
'organisation', 'READ_WORKINGDAYS', 'WORKINGDAYS', 'READ', '0'
|
||||
);
|
||||
|
||||
|
||||
INSERT INTO `m_permission` (
|
||||
`grouping` ,
|
||||
`code` ,
|
||||
`entity_name` ,
|
||||
`action_name` ,
|
||||
`can_maker_checker`
|
||||
)
|
||||
VALUES (
|
||||
'organisation', 'UPDATE_WORKINGDAYS', 'WORKINGDAYS', 'UPDATE', '0'
|
||||
);
|
||||
|
||||
INSERT INTO `m_permission` (
|
||||
`grouping` ,
|
||||
`code` ,
|
||||
`entity_name` ,
|
||||
`action_name` ,
|
||||
`can_maker_checker`
|
||||
)
|
||||
VALUES (
|
||||
'organisation', 'UPDATE_WORKINGDAYS_CHECKER', 'WORKINGDAYS', 'UPDATE_CHECKER', '0'
|
||||
);
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user