Business date part 1 (#2362)

Business date implementation - part 1
This commit is contained in:
Adam Saghy
2022-06-14 19:05:52 +02:00
committed by GitHub
parent a38fc32315
commit 4465e632f1
42 changed files with 1998 additions and 125 deletions
@@ -180,5 +180,8 @@ dependencyManagement {
entry 'json-path'
entry 'xml-path'
}
dependency 'org.mapstruct:mapstruct:1.5.1.Final'
dependency 'org.mapstruct:mapstruct-processor:1.5.1.Final'
}
}
+2 -1
View File
@@ -73,6 +73,7 @@ dependencies {
'org.springdoc:springdoc-openapi-ui',
'org.springdoc:springdoc-openapi-common',
'org.springdoc:springdoc-openapi-security',
'org.mapstruct:mapstruct',
)
implementation ('org.apache.commons:commons-email') {
@@ -128,7 +129,6 @@ dependencies {
exclude group: 'xml-apis'
}
runtimeOnly('org.glassfish.jaxb:jaxb-runtime') {
exclude group: 'com.sun.activation'
}
@@ -144,6 +144,7 @@ dependencies {
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
annotationProcessor 'org.mapstruct:mapstruct-processor'
// testCompile dependencies are ONLY used in src/test, not src/main.
// Do NOT repeat dependencies which are ALREADY in implementation or runtimeOnly!
@@ -3478,4 +3478,11 @@ public class CommandWrapperBuilder {
return this;
}
public CommandWrapperBuilder updateBusinessDate() {
this.actionName = "UPDATE";
this.entityName = "BUSINESS_DATE";
this.href = "/businessdate";
return this;
}
}
@@ -0,0 +1,107 @@
/**
* 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.businessdate.api;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.media.ArraySchema;
import io.swagger.v3.oas.annotations.media.Content;
import io.swagger.v3.oas.annotations.media.Schema;
import io.swagger.v3.oas.annotations.parameters.RequestBody;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.UriInfo;
import lombok.RequiredArgsConstructor;
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.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.springframework.stereotype.Component;
@RequiredArgsConstructor
@Path("businessdate")
@Component
@Tag(name = "Business Date Management", description = "Business date management enables you to set up, fetch and adjust organisation business dates")
public class BusinessDateApiResource {
private final ApiRequestParameterHelper parameterHelper;
private final PlatformSecurityContext securityContext;
private final DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer;
private final BusinessDateReadPlatformService readPlatformService;
private final PortfolioCommandSourceWritePlatformService commandWritePlatformService;
@GET
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "List all business dates", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(array = @ArraySchema(schema = @Schema(implementation = BusinessDateApiResourceSwagger.BusinessDateResponse.class)))) })
public String getBusinessDates(@Context final UriInfo uriInfo) {
securityContext.authenticatedUser().validateHasReadPermission("BUSINESS_DATE");
final List<BusinessDateData> foundBusinessDates = this.readPlatformService.findAll();
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
return this.jsonSerializer.serialize(settings, foundBusinessDates);
}
@GET
@Path("{type}")
@Consumes({ MediaType.TEXT_HTML, MediaType.APPLICATION_JSON })
@Produces(MediaType.APPLICATION_JSON)
@Operation(summary = "Retrieve a specific Business date", description = "")
@ApiResponses({
@ApiResponse(responseCode = "200", description = "OK", content = @Content(schema = @Schema(implementation = BusinessDateApiResourceSwagger.BusinessDateResponse.class))) })
public String getBusinessDate(@PathParam("type") @Parameter(description = "type") final String type, @Context final UriInfo uriInfo) {
securityContext.authenticatedUser().validateHasReadPermission("BUSINESS_DATE");
final BusinessDateData businessDate = this.readPlatformService.findByType(type);
ApiRequestJsonSerializationSettings settings = parameterHelper.process(uriInfo.getQueryParameters());
return this.jsonSerializer.serialize(settings, businessDate);
}
@POST
@Consumes({ MediaType.APPLICATION_JSON })
@Produces({ MediaType.APPLICATION_JSON })
@Operation(summary = "Update Business Date", description = "")
@RequestBody(required = true, content = @Content(schema = @Schema(implementation = BusinessDateApiResourceSwagger.BusinessDateRequest.class)))
@ApiResponses({
@ApiResponse(responseCode = "200", description = "", content = @Content(schema = @Schema(implementation = BusinessDateApiResourceSwagger.BusinessDateRequest.class))) })
public String updateBusinessDate(final String jsonRequestBody, @Context UriInfo uriInfo) {
securityContext.authenticatedUser().validateHasUpdatePermission("BUSINESS_DATE");
final CommandWrapper commandRequest = new CommandWrapperBuilder().updateBusinessDate().withJson(jsonRequestBody).build();
CommandProcessingResult result = commandWritePlatformService.logCommandSource(commandRequest);
return jsonSerializer.serialize(result);
}
}
@@ -0,0 +1,63 @@
/**
* 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.businessdate.api;
import io.swagger.v3.oas.annotations.media.Schema;
import java.time.LocalDate;
final class BusinessDateApiResourceSwagger {
private BusinessDateApiResourceSwagger() {
}
@Schema(description = "BusinessDateResponse")
public static final class BusinessDateResponse {
@Schema(example = "yyyy-MM-dd")
public String dateFormat;
@Schema(example = "COB date")
private String description;
@Schema(example = "COB_DATE")
private String type;
@Schema(example = "2015-02-15")
private LocalDate date;
private BusinessDateResponse() {
}
}
@Schema(description = "BusinessDateRequest")
public static final class BusinessDateRequest {
@Schema(example = "yyyy-MM-dd")
public String dateFormat;
@Schema(example = "COB_DATE")
private String type;
@Schema(example = "2015-02-15")
private LocalDate date;
@Schema(example = "en")
private String locale;
private BusinessDateRequest() {}
}
}
@@ -0,0 +1,45 @@
/**
* 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.businessdate.data;
import java.io.Serializable;
import java.time.LocalDate;
import lombok.Getter;
import lombok.ToString;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
@ToString
@Getter
public class BusinessDateData implements Serializable {
private String description;
private String type;
private LocalDate date;
public BusinessDateData(BusinessDateType businessDateType, LocalDate date) {
this.type = businessDateType.getName();
this.description = businessDateType.getDescription();
this.date = date;
}
public static BusinessDateData instance(BusinessDateType businessDateType, LocalDate value) {
return new BusinessDateData(businessDateType, value);
}
}
@@ -0,0 +1,64 @@
/**
* 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.businessdate.domain;
import java.time.LocalDate;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;
import javax.persistence.Version;
import javax.validation.constraints.NotNull;
import lombok.Getter;
import org.apache.fineract.infrastructure.core.domain.AbstractAuditableCustom;
@Getter
@Entity
@Table(name = "m_business_date", uniqueConstraints = { @UniqueConstraint(name = "uq_business_date_type", columnNames = { "type" }) })
public class BusinessDate extends AbstractAuditableCustom {
@Enumerated(EnumType.STRING)
@Column(name = "type")
private BusinessDateType type;
@Column(name = "date", columnDefinition = "DATE")
private LocalDate date;
@Version
private Long version;
protected BusinessDate() {
// TODO Auto-generated constructor stub
}
protected BusinessDate(@NotNull BusinessDateType type, @NotNull LocalDate date) {
this.type = type;
this.date = date;
}
public static BusinessDate instance(@NotNull BusinessDateType businessDateType, @NotNull LocalDate date) {
return new BusinessDate(businessDateType, date);
}
public void updateDate(LocalDate date) {
this.date = date;
}
}
@@ -0,0 +1,28 @@
/**
* 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.businessdate.domain;
import java.util.Optional;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
public interface BusinessDateRepository extends JpaRepository<BusinessDate, Long>, JpaSpecificationExecutor<BusinessDate> {
Optional<BusinessDate> findByType(BusinessDateType type);
}
@@ -0,0 +1,37 @@
/**
* 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.businessdate.domain;
import lombok.AllArgsConstructor;
import lombok.Getter;
@AllArgsConstructor
@Getter
public enum BusinessDateType {
BUSINESS_DATE(1, "Business Date"), COB_DATE(2, "Close of Business Date");
private final Integer id;
private final String description;
public String getName() {
return name();
}
}
@@ -0,0 +1,31 @@
/**
* 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.businessdate.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
/**
* A {@link RuntimeException} thrown when business date is violating any domain rule.
*/
public class BusinessDateActionException extends AbstractPlatformDomainRuleException {
public BusinessDateActionException(final String violationCode, String message) {
super(violationCode, message, violationCode);
}
}
@@ -0,0 +1,41 @@
/**
* 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.businessdate.exception;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformResourceNotFoundException;
/**
* A {@link RuntimeException} thrown when business date is not found.
*/
public class BusinessDateNotFoundException extends AbstractPlatformResourceNotFoundException {
public BusinessDateNotFoundException(String globalisationMessageCode, String defaultUserMessage, Object... defaultUserMessageArgs) {
super(globalisationMessageCode, defaultUserMessage, defaultUserMessageArgs);
}
public static BusinessDateNotFoundException notExist(final String type, Throwable... e) {
return new BusinessDateNotFoundException("error.msg.businessdate.type.not.exist",
"Business date with type `" + type + "` does not exist.", type, e);
}
public static BusinessDateNotFoundException notFound(final String type, Throwable... e) {
return new BusinessDateNotFoundException("error.msg.businessdate.not.found",
"Business date with type `" + type + "` does not found.", type, e);
}
}
@@ -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.
*/
package org.apache.fineract.infrastructure.businessdate.handler;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import org.apache.fineract.commands.annotation.CommandType;
import org.apache.fineract.commands.handler.NewCommandSourceHandler;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateWritePlatformService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@RequiredArgsConstructor
@Service
@CommandType(entity = "BUSINESS_DATE", action = "UPDATE")
public class BusinessDateUpdateHandler implements NewCommandSourceHandler {
private final BusinessDateWritePlatformService businessDateWritePlatformService;
@Transactional
@Override
public CommandProcessingResult processCommand(@NotNull final JsonCommand command) {
return businessDateWritePlatformService.updateBusinessDate(command);
}
}
@@ -0,0 +1,35 @@
/**
* 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.businessdate.mapper;
import java.util.List;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Mappings;
@Mapper(componentModel = "spring")
public interface BusinessDateMapper {
@Mappings({ @Mapping(target = "businessDateType", source = "source.type"), @Mapping(target = "date", source = "source.date") })
BusinessDateData map(BusinessDate source);
List<BusinessDateData> map(List<BusinessDate> sources);
}
@@ -0,0 +1,29 @@
/**
* 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.businessdate.service;
import java.util.List;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
public interface BusinessDateReadPlatformService {
List<BusinessDateData> findAll();
BusinessDateData findByType(String type);
}
@@ -0,0 +1,63 @@
/**
* 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.businessdate.service;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateRepository;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.exception.BusinessDateNotFoundException;
import org.apache.fineract.infrastructure.businessdate.mapper.BusinessDateMapper;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class BusinessDateReadPlatformServiceImpl implements BusinessDateReadPlatformService {
private final BusinessDateRepository repository;
private final BusinessDateMapper mapper;
@Override
public List<BusinessDateData> findAll() {
List<BusinessDate> businessDateList = repository.findAll();
return mapper.map(businessDateList);
}
@Override
public BusinessDateData findByType(String type) {
BusinessDateType businessDateType;
try {
businessDateType = BusinessDateType.valueOf(type);
} catch (IllegalArgumentException e) {
log.error("Provided business date type cannot be found: {}", type);
throw BusinessDateNotFoundException.notExist(type, e);
}
Optional<BusinessDate> businessDate = repository.findByType(businessDateType);
if (businessDate.isEmpty()) {
log.error("Business date with the provided type cannot be found {}", type);
throw BusinessDateNotFoundException.notFound(type);
}
return mapper.map(businessDate.get());
}
}
@@ -0,0 +1,32 @@
/**
* 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.businessdate.service;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
public interface BusinessDateWritePlatformService {
CommandProcessingResult updateBusinessDate(JsonCommand command);
void increaseCOBDateByOneDay() throws JobExecutionException;
void increaseBusinessDateByOneDay() throws JobExecutionException;
}
@@ -0,0 +1,149 @@
/**
* 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.businessdate.service;
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateRepository;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.exception.BusinessDateActionException;
import org.apache.fineract.infrastructure.businessdate.validator.BusinessDateDataParserAndValidator;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.ApiParameterError;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResultBuilder;
import org.apache.fineract.infrastructure.core.exception.AbstractPlatformDomainRuleException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.jobs.annotation.CronTarget;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.springframework.stereotype.Service;
@Slf4j
@Service
@RequiredArgsConstructor
public class BusinessDateWritePlatformServiceImpl implements BusinessDateWritePlatformService {
private final BusinessDateDataParserAndValidator dataValidator;
private final BusinessDateRepository repository;
private final ConfigurationDomainService configurationDomainService;
@Override
public CommandProcessingResult updateBusinessDate(@NotNull final JsonCommand command) {
BusinessDateData data = dataValidator.validateAndParseUpdate(command);
Map<String, Object> changes = new HashMap<>();
adjustDate(data, changes);
return new CommandProcessingResultBuilder().withCommandId(command.commandId()).with(changes).build();
}
private void adjustDate(BusinessDateData data, Map<String, Object> changes) {
boolean isCOBDateAdjustmentEnabled = configurationDomainService.isCOBDateAdjustmentEnabled();
boolean isBusinessDateEnabled = configurationDomainService.isBusinessDateEnabled();
if (!isBusinessDateEnabled) {
log.error("Business date functionality is not enabled!");
throw new BusinessDateActionException("business.date.is.not.enabled", "Business date functionality is not enabled");
}
updateOrCreateBusinessDate(data.getType(), data.getDate(), changes);
if (isCOBDateAdjustmentEnabled && BusinessDateType.BUSINESS_DATE.name().equals(data.getType())) {
updateOrCreateBusinessDate(BusinessDateType.COB_DATE.getName(), data.getDate().minus(1, ChronoUnit.DAYS), changes);
}
}
@Override
@CronTarget(jobName = JobName.INCREASE_COB_DATE_BY_1_DAY)
public void increaseCOBDateByOneDay() throws JobExecutionException {
increaseDateByTypeByOneDay(BusinessDateType.COB_DATE);
}
@Override
@CronTarget(jobName = JobName.INCREASE_BUSINESS_DATE_BY_1_DAY)
public void increaseBusinessDateByOneDay() throws JobExecutionException {
increaseDateByTypeByOneDay(BusinessDateType.BUSINESS_DATE);
}
private void increaseDateByTypeByOneDay(BusinessDateType businessDateType) throws JobExecutionException {
List<Throwable> exceptions = new ArrayList<>();
Map<String, Object> changes = new HashMap<>();
Optional<BusinessDate> businessDateEntity = repository.findByType(businessDateType);
LocalDate businessDate = businessDateEntity.map(BusinessDate::getDate).orElse(DateUtils.getLocalDateOfTenant());
businessDate = businessDate.plusDays(1);
try {
BusinessDateData businessDateData = BusinessDateData.instance(businessDateType, businessDate);
adjustDate(businessDateData, changes);
} catch (final PlatformApiDataValidationException e) {
final List<ApiParameterError> errors = e.getErrors();
for (final ApiParameterError error : errors) {
log.error("Increasing {} by 1 day failed due to: {}", businessDateType.getDescription(), error.getDeveloperMessage());
}
exceptions.add(e);
} catch (final AbstractPlatformDomainRuleException e) {
log.error("Increasing {} by 1 day failed due to: {}", businessDateType.getDescription(), e.getDefaultUserMessage());
exceptions.add(e);
} catch (Exception e) {
log.error("Increasing {} by 1 day failed due to: {}", businessDateType.getDescription(), e.getMessage());
exceptions.add(e);
}
if (!exceptions.isEmpty()) {
throw new JobExecutionException(exceptions);
}
}
private void updateOrCreateBusinessDate(String type, LocalDate newDate, Map<String, Object> changes) {
BusinessDateType businessDateType = BusinessDateType.valueOf(type);
Optional<BusinessDate> businessDate = repository.findByType(businessDateType);
if (businessDate.isEmpty()) {
BusinessDate newBusinessDate = BusinessDate.instance(businessDateType, newDate);
repository.save(newBusinessDate);
changes.put(type, newBusinessDate.getDate());
} else {
updateBusinessDate(businessDate.get(), newDate, changes);
}
}
private void updateBusinessDate(BusinessDate businessDate, LocalDate newDate, Map<String, Object> changes) {
LocalDate oldDate = businessDate.getDate();
if (!hasChange(oldDate, newDate)) {
return;
}
businessDate.updateDate(newDate);
repository.save(businessDate);
changes.put(businessDate.getType().name(), newDate);
}
private boolean hasChange(@NotNull LocalDate oldDate, @NotNull LocalDate date) {
return (date.isBefore(oldDate) || date.isAfter(oldDate));
}
}
@@ -0,0 +1,107 @@
/**
* 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.businessdate.validator;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import javax.validation.constraints.NotNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder;
import org.apache.fineract.infrastructure.core.exception.InvalidJsonException;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.springframework.stereotype.Component;
@Slf4j
@RequiredArgsConstructor
@Component
public class BusinessDateDataParserAndValidator {
private final FromJsonHelper jsonHelper;
public BusinessDateData validateAndParseUpdate(@NotNull final JsonCommand command) {
final DataValidatorBuilder dataValidator = new DataValidatorBuilder(new ArrayList<>()).resource("businessdate.update");
JsonObject element = extractJsonObject(command);
BusinessDateData result = validateAndParseUpdate(dataValidator, element, jsonHelper);
throwExceptionIfValidationWarningsExist(dataValidator);
return result;
}
private JsonObject extractJsonObject(JsonCommand command) {
String json = command.json();
if (StringUtils.isBlank(json)) {
throw new InvalidJsonException();
}
final JsonElement element = jsonHelper.parse(json);
return element.getAsJsonObject();
}
private void throwExceptionIfValidationWarningsExist(DataValidatorBuilder dataValidator) {
if (dataValidator.hasError()) {
log.error("Business date - Validation errors: {}", dataValidator.getDataValidationErrors());
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
dataValidator.getDataValidationErrors());
}
}
private BusinessDateData validateAndParseUpdate(final DataValidatorBuilder dataValidator, JsonObject element,
FromJsonHelper jsonHelper) {
if (element == null) {
return null;
}
jsonHelper.checkForUnsupportedParameters(element, List.of("type", "date", "dateFormat", "locale"));
String businessDateTypeName = jsonHelper.extractStringNamed("type", element);
final String localeValue = jsonHelper.extractStringNamed("locale", element);
final String dateFormat = jsonHelper.extractDateFormatParameter(element);
final String dateValue = jsonHelper.extractStringNamed("date", element);
dataValidator.reset().parameter("type").value(businessDateTypeName).notBlank();
dataValidator.reset().parameter("locale").value(localeValue).notBlank();
dataValidator.reset().parameter("dateFormat").value(dateFormat).notBlank();
dataValidator.reset().parameter("date").value(dateValue).notBlank();
if (dataValidator.hasError()) {
return null;
}
Locale locale = jsonHelper.extractLocaleParameter(element);
BusinessDateType type;
try {
type = BusinessDateType.valueOf(businessDateTypeName);
} catch (IllegalArgumentException e) {
dataValidator.reset().parameter("type").failWithCode("Invalid Business Type value: `" + businessDateTypeName + "`");
return null;
}
LocalDate date = jsonHelper.extractLocalDateNamed("date", element, dateFormat, locale);
dataValidator.reset().parameter("date").value(date).notNull();
return dataValidator.hasError() ? null : BusinessDateData.instance(type, date);
}
}
@@ -112,4 +112,8 @@ public interface ConfigurationDomainService {
boolean isRelaxingDaysConfigForPivotDateEnabled();
Long retrieveRelaxingDaysConfigForPivotDate();
boolean isBusinessDateEnabled();
boolean isCOBDateAdjustmentEnabled();
}
@@ -38,6 +38,8 @@ import org.springframework.transaction.annotation.Transactional;
@Service
public class ConfigurationDomainServiceJpa implements ConfigurationDomainService {
public static final String ENABLE_BUSINESS_DATE = "enable_business_date";
public static final String ENABLE_AUTOMATIC_COB_DATE_ADJUSTMENT = "enable_automatic_cob_date_adjustment";
private final PermissionRepository permissionRepository;
private final GlobalConfigurationRepositoryWrapper globalConfigurationRepository;
private final PlatformCacheRepository cacheTypeRepository;
@@ -432,4 +434,13 @@ public class ConfigurationDomainServiceJpa implements ConfigurationDomainService
return property.isEnabled();
}
@Override
public boolean isBusinessDateEnabled() {
return getGlobalConfigurationPropertyData(ENABLE_BUSINESS_DATE).isEnabled();
}
@Override
public boolean isCOBDateAdjustmentEnabled() {
return getGlobalConfigurationPropertyData(ENABLE_AUTOMATIC_COB_DATE_ADJUSTMENT).isEnabled();
}
}
@@ -175,6 +175,11 @@ public final class JsonCommand {
this.organisationCreditBureauId = null;
}
public static JsonCommand from(final String jsonCommand) {
return new JsonCommand(null, jsonCommand, null, null, null, null, null, null, null, null, null, null, null, null, null, null);
}
public Long getOrganisationCreditBureauId() {
return this.organisationCreditBureauId;
}
@@ -133,6 +133,6 @@ public final class ApiParameterError {
@Override
public String toString() {
return "ApiParameterError{developerMessage=" + developerMessage + "; ... }";
return developerMessage;
}
}
@@ -21,10 +21,12 @@ package org.apache.fineract.infrastructure.core.data;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import lombok.ToString;
/**
* Represents the successful result of an REST API call that results in processing a command.
*/
@ToString
public class CommandProcessingResult implements Serializable {
private Long commandId;
@@ -115,8 +115,8 @@ public class DataValidatorBuilder {
if (StringUtils.isBlank(linkedValue)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(linkedParameterName).append(".cannot.be.empty.when.").append(this.parameter).append(".is.populated");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(linkedParameterName)
.append(" cannot be empty when ").append(this.parameter).append(" is populated.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(linkedParameterName)
.append("` cannot be empty when ").append(this.parameter).append(" is populated.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), linkedParameterName, linkedValue, this.value);
this.dataValidationErrors.add(error);
@@ -149,8 +149,8 @@ public class DataValidatorBuilder {
if (this.value != null && !this.value.equals(linkedValue)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(linkedParameterName).append(".not.equal.to.").append(this.parameter);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(linkedParameterName)
.append(" is not equal to ").append(this.parameter).append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(linkedParameterName)
.append("` is not equal to ").append(this.parameter).append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), linkedParameterName, linkedValue, this.value);
this.dataValidationErrors.add(error);
@@ -166,8 +166,8 @@ public class DataValidatorBuilder {
if (this.value != null && this.value.equals(linkedValue)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(linkedParameterName).append(".same.as.").append(this.parameter);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(linkedParameterName)
.append(" is same as ").append(this.parameter).append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(linkedParameterName)
.append("` is same as ").append(this.parameter).append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), linkedParameterName, linkedValue, this.value);
this.dataValidationErrors.add(error);
@@ -184,8 +184,8 @@ public class DataValidatorBuilder {
if (!trueOfFalseFieldProvided && !this.ignoreNullValue) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".must.be.true.or.false");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be set as true or false.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be set as true or false.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter);
this.dataValidationErrors.add(error);
@@ -199,8 +199,8 @@ public class DataValidatorBuilder {
if (!trueOfFalseField.toString().equalsIgnoreCase("true") && !trueOfFalseField.toString().equalsIgnoreCase("false")) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".must.be.true.or.false");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be set as true or false.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be set as true or false.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter);
this.dataValidationErrors.add(error);
@@ -223,8 +223,8 @@ public class DataValidatorBuilder {
}
validationErrorCode.append(".cannot.be.blank");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(realParameterName)
.append(" is mandatory.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(realParameterName)
.append("` is mandatory.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), realParameterName, this.arrayIndex);
this.dataValidationErrors.add(error);
@@ -248,8 +248,8 @@ public class DataValidatorBuilder {
}
validationErrorCode.append(".cannot.be.blank");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(realParameterName)
.append(" is mandatory.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(realParameterName)
.append("` is mandatory.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), realParameterName, this.arrayIndex);
this.dataValidationErrors.add(error);
@@ -265,8 +265,8 @@ public class DataValidatorBuilder {
if (this.value != null && this.value.toString().trim().length() > maxLength) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".exceeds.max.length");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" exceeds max length of ").append(maxLength).append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` exceeds max length of ").append(maxLength).append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, maxLength, this.value.toString());
this.dataValidationErrors.add(error);
@@ -284,8 +284,8 @@ public class DataValidatorBuilder {
if (number < min || number > max) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.within.expected.range");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be between ").append(min).append(" and ").append(max).append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be between ").append(min).append(" and ").append(max).append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, min, max);
this.dataValidationErrors.add(error);
@@ -305,8 +305,8 @@ public class DataValidatorBuilder {
if (this.value == null || !valuesList.contains(this.value)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.one.of.expected.enumerations");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value, values);
@@ -333,8 +333,8 @@ public class DataValidatorBuilder {
if (this.value == null || !valuesList.contains(this.value.toString().toLowerCase())) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.one.of.expected.enumerations");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value, values);
@@ -357,8 +357,8 @@ public class DataValidatorBuilder {
if (this.value == null || !valuesListLowercase.contains(this.value.toString().toLowerCase())) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.one.of.expected.enumerations");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be one of [ ").append(valuesListStr).append(" ] ").append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value, valuesList);
@@ -381,8 +381,8 @@ public class DataValidatorBuilder {
if (valuesList.contains(this.value)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.one.of.unwanted.enumerations");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must not be any of [ ").append(valuesListStr).append(" ] ").append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must not be any of [ ").append(valuesListStr).append(" ] ").append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value, values);
@@ -403,8 +403,8 @@ public class DataValidatorBuilder {
if (number.compareTo(BigDecimal.ZERO) <= 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.zero");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than 0.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than 0.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -426,8 +426,8 @@ public class DataValidatorBuilder {
if (number.compareTo(BigDecimal.ZERO) < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.zero.or.greater");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than or equal to 0.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than or equal to 0.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -449,8 +449,8 @@ public class DataValidatorBuilder {
if (number < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.zero.or.greater");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be zero or greater.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be zero or greater.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -472,8 +472,8 @@ public class DataValidatorBuilder {
if (number < 1) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.zero");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than 0.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than 0.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -492,8 +492,8 @@ public class DataValidatorBuilder {
if (intValue < number + 1) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.specified.number");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than ").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than ").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, intValue, number);
this.dataValidationErrors.add(error);
@@ -512,8 +512,8 @@ public class DataValidatorBuilder {
if (intValue < number) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.equal.to.or.greater.than.specified.number");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be equal to or greater than").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be equal to or greater than").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, intValue, number);
this.dataValidationErrors.add(error);
@@ -532,8 +532,8 @@ public class DataValidatorBuilder {
if (!intValue.equals(number)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.equal.to.specified.number");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be same as").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be same as").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, intValue, number);
this.dataValidationErrors.add(error);
@@ -552,8 +552,8 @@ public class DataValidatorBuilder {
if (intValue < number || intValue % number != 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.in.multiples.of.specified.number");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be multiples of ").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be multiples of ").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, intValue, number);
this.dataValidationErrors.add(error);
@@ -575,8 +575,8 @@ public class DataValidatorBuilder {
if (number < 1) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.zero");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than 0.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than 0.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -598,8 +598,8 @@ public class DataValidatorBuilder {
if (number < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.equal.or.greater.than.zero");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be equal or greater than 0.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be equal or greater than 0.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, 0);
this.dataValidationErrors.add(error);
@@ -618,8 +618,8 @@ public class DataValidatorBuilder {
if (longValue < number + 1) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.specified.number");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than ").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than ").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, longValue, number);
this.dataValidationErrors.add(error);
@@ -638,8 +638,8 @@ public class DataValidatorBuilder {
if (longValue < number + 1) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".not.greater.than.specified.").append(paramName).append(".at Index.").append(index);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be greater than ").append(number);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than ").append(number);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, longValue, number);
this.dataValidationErrors.add(error);
@@ -657,8 +657,8 @@ public class DataValidatorBuilder {
if (ObjectUtils.isEmpty(array)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".cannot.be.empty");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" cannot be empty. You must select at least one.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` cannot be empty. You must select at least one.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter);
this.dataValidationErrors.add(error);
@@ -675,8 +675,8 @@ public class DataValidatorBuilder {
if (this.value != null && !array.iterator().hasNext()) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".cannot.be.empty");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" cannot be empty. You must select at least one.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` cannot be empty. You must select at least one.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter);
this.dataValidationErrors.add(error);
@@ -687,7 +687,8 @@ public class DataValidatorBuilder {
public void expectedArrayButIsNot() {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.an.array");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter).append(" is not an array.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` is not an array.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter);
this.dataValidationErrors.add(error);
@@ -716,8 +717,8 @@ public class DataValidatorBuilder {
public DataValidatorBuilder inValidValue(final String parameterValueCode, final Object invalidValue) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".invalid.").append(parameterValueCode);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" has an invalid value.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` has an invalid value.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, invalidValue);
this.dataValidationErrors.add(error);
@@ -740,8 +741,8 @@ public class DataValidatorBuilder {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".cannot.also.be.provided.when.").append(parameterName).append(".is.populated");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" cannot also be provided when ").append(parameterName).append(" is populated.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` cannot also be provided when `").append(parameterName).append("` is populated.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, this.value, parameterName, parameterValue);
this.dataValidationErrors.add(error);
@@ -765,8 +766,8 @@ public class DataValidatorBuilder {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".cannot.also.be.provided.when.").append(parameterName).append(".is.")
.append(parameterValue);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" cannot also be provided when ").append(parameterName).append(" is ").append(parameterValue);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` cannot also be provided when `").append(parameterName).append("` is ").append(parameterValue);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, this.value, parameterName, parameterValue);
this.dataValidationErrors.add(error);
@@ -780,21 +781,22 @@ public class DataValidatorBuilder {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".must.be.provided.when.").append(parameterName).append(".is.").append(parameterValue);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must be provided when ").append(parameterName).append(" is ").append(parameterValue);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be provided when `").append(parameterName).append("` is ").append(parameterValue);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(), defaultEnglishMessage.toString(),
this.parameter, this.value, parameterName, parameterValue);
this.dataValidationErrors.add(error);
return this;
}
public DataValidatorBuilder comapareMinimumAndMaximumAmounts(final BigDecimal minimumBalance, final BigDecimal maximumBalance) {
public DataValidatorBuilder compareMinimumAndMaximumAmounts(final BigDecimal minimumBalance, final BigDecimal maximumBalance) {
if (minimumBalance != null && maximumBalance != null) {
if (maximumBalance.compareTo(minimumBalance) < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.within.expected.range");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(" minimum amount ")
.append(minimumBalance).append(" should less than maximum amount ").append(maximumBalance).append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` minimum amount ").append(minimumBalance).append(" should less than the maximum amount ")
.append(maximumBalance).append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, minimumBalance, maximumBalance);
this.dataValidationErrors.add(error);
@@ -810,7 +812,7 @@ public class DataValidatorBuilder {
if (amount.compareTo(minimumAmount) < 0 || amount.compareTo(maximumAmount) > 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".amount.is.not.within.min.max.range");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter).append(" amount ")
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter).append("` amount ")
.append(amount).append(" must be between ").append(minimumAmount).append(" and ").append(maximumAmount)
.append(" .");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
@@ -828,8 +830,8 @@ public class DataValidatorBuilder {
if (amount.compareTo(min) < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.less.than.min");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter).append(" value ")
.append(amount).append(" must not be less than minimum value ").append(min);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter).append("` value ")
.append(amount).append(" must not be less than the minimum value ").append(min);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, amount, min);
this.dataValidationErrors.add(error);
@@ -845,7 +847,7 @@ public class DataValidatorBuilder {
if (amount.compareTo(max) > 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.max");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter).append(" value ")
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter).append("` value ")
.append(amount).append(" must not be more than maximum value ").append(max);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, amount, max);
@@ -856,7 +858,7 @@ public class DataValidatorBuilder {
return this;
}
public DataValidatorBuilder comapareMinAndMaxOfTwoBigDecmimalNos(final BigDecimal min, final BigDecimal max) {
public DataValidatorBuilder compareMinAndMaxOfTwoBigDecmimalNos(final BigDecimal min, final BigDecimal max) {
if (min != null && max != null) {
if (max.compareTo(min) < 0) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
@@ -884,7 +886,7 @@ public class DataValidatorBuilder {
return this;
} catch (final ParseException e) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.recurring.rule.parsing.error",
"Error in pasring the Recurring Rule value: " + recurringRule + ".", this.parameter, recurringRule);
"Error in parsing the Recurring Rule value: " + recurringRule + ".", this.parameter, recurringRule);
this.dataValidationErrors.add(error);
return this;
}
@@ -902,8 +904,8 @@ public class DataValidatorBuilder {
if (number < min) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.less.than.min");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be greater than minimum value ").append(min);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than the minimum value ").append(min);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, min);
this.dataValidationErrors.add(error);
@@ -922,8 +924,8 @@ public class DataValidatorBuilder {
if (number > max) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.max");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be less than maximum value ").append(max);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be less than the maximum value ").append(max);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, number, max);
this.dataValidationErrors.add(error);
@@ -940,8 +942,8 @@ public class DataValidatorBuilder {
if (this.value != null && !this.value.toString().matches(expression)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".does.not.match.regexp");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" must match the provided regular expression [ ").append(expression).append(" ] ").append(".");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must match the provided regular expression [ ").append(expression).append(" ] ").append(".");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value, expression);
@@ -986,8 +988,8 @@ public class DataValidatorBuilder {
if (validationErr) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".value.should.true.or.false");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" value should true or false ");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` value should true or false ");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value);
this.dataValidationErrors.add(error);
@@ -1017,8 +1019,8 @@ public class DataValidatorBuilder {
if (validationErr) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".format.is.invalid");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.resource).append(this.parameter)
.append(" is in invalid format, should contain '-','+','()' and numbers only.");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` is in invalid format, should contain '-','+','()' and numbers only.");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value);
this.dataValidationErrors.add(error);
@@ -1030,8 +1032,8 @@ public class DataValidatorBuilder {
if (this.value != null && !CronExpression.isValidExpression(this.value.toString().trim())) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".invalid");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter ").append(this.parameter)
.append(" value is not a valid cron expression");
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` value is not a valid cron expression");
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, this.value);
this.dataValidationErrors.add(error);
@@ -1049,8 +1051,8 @@ public class DataValidatorBuilder {
if (date.isAfter(dateVal)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.less.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be greter than provided date").append(date);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be greater than the provided date").append(date);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
this.dataValidationErrors.add(error);
@@ -1069,8 +1071,8 @@ public class DataValidatorBuilder {
if (date.isBefore(dateVal)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be less than provided date").append(date);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be less than the provided date").append(date);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
this.dataValidationErrors.add(error);
@@ -1089,8 +1091,8 @@ public class DataValidatorBuilder {
if (dateVal.isAfter(date)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.greater.than.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be less than or equal to provided date").append(date);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be less than or equal to the provided date").append(date);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
this.dataValidationErrors.add(error);
@@ -1109,8 +1111,8 @@ public class DataValidatorBuilder {
if (!dateVal.isEqual(date)) {
final StringBuilder validationErrorCode = new StringBuilder("validation.msg.").append(this.resource).append(".")
.append(this.parameter).append(".is.not.equal.to.date");
final StringBuilder defaultEnglishMessage = new StringBuilder("The ").append(this.parameter)
.append(" must be equal to provided date").append(date);
final StringBuilder defaultEnglishMessage = new StringBuilder("The parameter `").append(this.parameter)
.append("` must be equal to the provided date").append(date);
final ApiParameterError error = ApiParameterError.parameterError(validationErrorCode.toString(),
defaultEnglishMessage.toString(), this.parameter, dateVal, date);
this.dataValidationErrors.add(error);
@@ -59,4 +59,9 @@ public class PlatformApiDataValidationException extends AbstractPlatformExceptio
public List<ApiParameterError> getErrors() {
return this.errors;
}
@Override
public String toString() {
return "PlatformApiDataValidationException{" + "errors=" + errors + '}';
}
}
@@ -30,7 +30,7 @@ import org.springframework.stereotype.Component;
* into JSON.
*/
@Component
public final class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<T> {
public class DefaultToApiJsonSerializer<T> implements ToApiJsonSerializer<T> {
private final ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOff;
private final ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson excludeNothingWithPrettyPrintingOn;
@@ -36,6 +36,7 @@ import java.time.LocalDateTime;
import java.time.MonthDay;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeFormatterBuilder;
import java.time.format.DateTimeParseException;
import java.time.temporal.ChronoField;
import java.util.ArrayList;
import java.util.Arrays;
@@ -349,8 +350,8 @@ public class JsonParserHelper {
} catch (final IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.month.day",
"The parameter " + parameterName + " is invalid based on the monthDayFormat: '" + dateFormat
+ "' and locale: '" + clientApplicationLocale + "' provided:",
"The parameter `" + parameterName + "` is invalid based on the monthDayFormat: `" + dateFormat
+ "` and locale: `" + clientApplicationLocale + "` provided:",
parameterName, valueAsString, dateFormat);
dataValidationErrors.add(error);
@@ -422,7 +423,7 @@ public class JsonParserHelper {
}
} catch (IllegalArgumentException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder("The parameter '" + timeValueAsString + "' is not in correct format.")
final String defaultMessage = new StringBuilder("The parameter `" + timeValueAsString + "` is not in correct format.")
.toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.TimeFormat", defaultMessage,
parameterName);
@@ -475,12 +476,12 @@ public class JsonParserHelper {
.parseDefaulting(ChronoField.HOUR_OF_DAY, 0).parseDefaulting(ChronoField.MINUTE_OF_HOUR, 0)
.parseDefaulting(ChronoField.SECOND_OF_MINUTE, 0).toFormatter(clientApplicationLocale);
eventLocalDateTime = LocalDateTime.parse(dateTimeAsString, formatter);
} catch (final IllegalArgumentException e) {
} catch (final IllegalArgumentException | DateTimeParseException e) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError
.parameterError("validation.msg.invalid.dateFormat.format",
"The parameter " + parameterName + " is invalid based on the dateFormat: '" + dateTimeFormat
+ "' and locale: '" + clientApplicationLocale + "' provided:",
"The parameter `" + parameterName + "` is invalid based on the dateFormat: `" + dateTimeFormat
+ "` and locale: `" + clientApplicationLocale + "` provided:",
parameterName, eventLocalDateTime, dateTimeFormat);
dataValidationErrors.add(error);
@@ -499,14 +500,14 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
if (StringUtils.isBlank(dateFormat)) {
final String defaultMessage = new StringBuilder(
"The parameter '" + parameterName + "' requires a 'dateFormat' parameter to be passed with it.").toString();
"The parameter `" + parameterName + "` requires a `dateFormat` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.dateFormat.parameter",
defaultMessage, parameterName);
dataValidationErrors.add(error);
}
if (clientApplicationLocale == null) {
final String defaultMessage = new StringBuilder(
"The parameter '" + parameterName + "' requires a 'locale' parameter to be passed with it.").toString();
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
@@ -524,7 +525,7 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder(
"The parameter '" + parameterName + "' requires a 'locale' parameter to be passed with it.").toString();
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
@@ -572,7 +573,7 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.integer.format",
"The parameter " + parameterName + " has value: " + numericalValueFormatted
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted
+ " which is invalid integer value for provided locale of [" + clientApplicationLocale.toString() + "].",
parameterName, numericalValueFormatted, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
@@ -596,7 +597,7 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.integer",
"The parameter " + parameterName + " has value: " + numericalValueFormatted + " which is invalid integer.",
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted + " which is invalid integer.",
parameterName, numericalValueFormatted, numericalValueFormatted);
dataValidationErrors.add(error);
@@ -611,7 +612,7 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final String defaultMessage = new StringBuilder(
"The parameter '" + parameterName + "' requires a 'locale' parameter to be passed with it.").toString();
"The parameter `" + parameterName + "` requires a `locale` parameter to be passed with it.").toString();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.missing.locale.parameter", defaultMessage,
parameterName);
dataValidationErrors.add(error);
@@ -650,8 +651,8 @@ public class JsonParserHelper {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterErrorWithValue("validation.msg.invalid.decimal.format",
"The parameter " + parameterName + " has value: " + numericalValueFormatted
+ " which is invalid decimal value for provided locale of [" + clientApplicationLocale.toString() + "].",
"The parameter `" + parameterName + "` has value: " + numericalValueFormatted
+ " which is invalid decimal value for provided locale of [" + clientApplicationLocale + "].",
parameterName, numericalValueFormatted, numericalValueFormatted, clientApplicationLocale);
dataValidationErrors.add(error);
@@ -668,7 +669,7 @@ public class JsonParserHelper {
if (StringUtils.isBlank(localeAsString)) {
final List<ApiParameterError> dataValidationErrors = new ArrayList<>();
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale is invalid. It cannot be blank.", "locale");
"The parameter `locale` is invalid. It cannot be blank.", "locale");
dataValidationErrors.add(error);
throw new PlatformApiDataValidationException("validation.msg.validation.errors.exist", "Validation errors exist.",
@@ -706,7 +707,7 @@ public class JsonParserHelper {
final List<String> allowedLanguages = Arrays.asList(Locale.getISOLanguages());
if (!allowedLanguages.contains(languageCode.toLowerCase())) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale has an invalid language value " + languageCode + " .", "locale", languageCode);
"The parameter `locale` has an invalid language value " + languageCode + " .", "locale", languageCode);
dataValidationErrors.add(error);
}
@@ -714,7 +715,7 @@ public class JsonParserHelper {
final List<String> allowedCountries = Arrays.asList(Locale.getISOCountries());
if (!allowedCountries.contains(courntryCode)) {
final ApiParameterError error = ApiParameterError.parameterError("validation.msg.invalid.locale.format",
"The parameter locale has an invalid country value " + courntryCode + " .", "locale", courntryCode);
"The parameter `locale` has an invalid country value " + courntryCode + " .", "locale", courntryCode);
dataValidationErrors.add(error);
}
}
@@ -45,9 +45,11 @@ public enum JobName {
"Get Delivery Reports from SMS Gateway"), GENERATE_ADHOCCLIENT_SCEHDULE(
"Generate AdhocClient Schedule"), UPDATE_EMAIL_OUTBOUND_WITH_CAMPAIGN_MESSAGE(
"Update Email Outbound with campaign message"), EXECUTE_EMAIL(
"Execute Email"), UPDATE_TRAIL_BALANCE_DETAILS(
"Execute Email"), UPDATE_TRIAL_BALANCE_DETAILS(
"Update Trial Balance Details"), EXECUTE_DIRTY_JOBS(
"Execute All Dirty Jobs");
"Execute All Dirty Jobs"), INCREASE_BUSINESS_DATE_BY_1_DAY(
"Increase Business Date by 1 day"), INCREASE_COB_DATE_BY_1_DAY(
"Increase COB Date by 1 day");
private final String name;
@@ -151,7 +151,7 @@ public class AdHocQueryDataValidator {
.extractBigDecimalWithLocaleNamed(AdHocQuerySearchConstants.maxOutStandingAmountPercentageParamName, element);
baseDataValidator.reset().parameter(AdHocQuerySearchConstants.maxOutStandingAmountPercentageParamName)
.value(maxOutStandingAmountPercentage).notNull().notLessThanMin(BigDecimal.ZERO);
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(minOutStandingAmountPercentage,
baseDataValidator.reset().compareMinAndMaxOfTwoBigDecmimalNos(minOutStandingAmountPercentage,
maxOutStandingAmountPercentage);
} else {
if (this.fromApiJsonHelper.parameterExists(AdHocQuerySearchConstants.outStandingAmountPercentageParamName, element)) {
@@ -184,7 +184,7 @@ public class AdHocQueryDataValidator {
.extractBigDecimalWithLocaleNamed(AdHocQuerySearchConstants.maxOutstandingAmountParamName, element);
baseDataValidator.reset().parameter(AdHocQuerySearchConstants.maxOutstandingAmountParamName).value(maxOutstandingAmount)
.notNull().notLessThanMin(BigDecimal.ZERO);
baseDataValidator.reset().comapareMinAndMaxOfTwoBigDecmimalNos(minOutstandingAmount, maxOutstandingAmount);
baseDataValidator.reset().compareMinAndMaxOfTwoBigDecmimalNos(minOutstandingAmount, maxOutstandingAmount);
} else {
final BigDecimal outstandingAmount = this.fromApiJsonHelper
.extractBigDecimalWithLocaleNamed(AdHocQuerySearchConstants.outstandingAmountParamName, element);
@@ -20,7 +20,6 @@ package org.apache.fineract.scheduledjobs.service;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@@ -329,7 +328,7 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
}
@Override
@CronTarget(jobName = JobName.UPDATE_TRAIL_BALANCE_DETAILS)
@CronTarget(jobName = JobName.UPDATE_TRIAL_BALANCE_DETAILS)
public void updateTrialBalanceDetails() throws JobExecutionException {
final JdbcTemplate jdbcTemplate = new JdbcTemplate(this.dataSourceServiceFactory.determineDataSourceService().retrieveDataSource());
final StringBuilder tbGapSqlBuilder = new StringBuilder(500);
@@ -344,15 +343,14 @@ public class ScheduledJobRunnerServiceImpl implements ScheduledJobRunnerService
if (days < 1) {
continue;
}
final String formattedDate = new SimpleDateFormat("yyyy-MM-dd").format(tbGap);
final StringBuilder sqlBuilder = new StringBuilder(600);
sqlBuilder.append("Insert Into m_trial_balance(office_id, account_id, Amount, entry_date, created_date,closing_balance) ")
.append("Select je.office_id, je.account_id, SUM(CASE WHEN je.type_enum=1 THEN (-1) * je.amount ELSE je.amount END) ")
.append("as Amount, Date(je.entry_date) as 'Entry_Date', je.transaction_date as 'Created_Date',sum(je.amount) as closing_balance ")
.append("as Amount, Date(je.entry_date) as Entry_Date, je.transaction_date as Created_Date,sum(je.amount) as closing_balance ")
.append("from acc_gl_journal_entry je WHERE je.transaction_date = ? ")
.append("group by je.account_id, je.office_id, je.transaction_date, Date(je.entry_date)");
final int result = jdbcTemplate.update(sqlBuilder.toString(), formattedDate);
final int result = jdbcTemplate.update(sqlBuilder.toString(), tbGap);
LOG.info("{}: Records affected by updateTrialBalanceDetails: {}", ThreadLocalContextUtil.getTenant().getName(), result);
}
@@ -552,9 +552,20 @@ public class AppUser extends AbstractPersistableCustom implements PlatformUser {
}
public void validateHasReadPermission(final String resourceType) {
validateHasPermission("READ", resourceType);
}
final String authorizationMessage = "User has no authority to view " + resourceType.toLowerCase() + "s";
final String matchPermission = "READ_" + resourceType.toUpperCase();
public void validateHasCreatePermission(final String resourceType) {
validateHasPermission("CREATE", resourceType);
}
public void validateHasUpdatePermission(final String resourceType) {
validateHasPermission("UPDATE", resourceType);
}
private void validateHasPermission(final String prefix, final String resourceType) {
final String authorizationMessage = "User has no authority to " + prefix + " " + resourceType.toLowerCase() + "s";
final String matchPermission = prefix + "_" + resourceType.toUpperCase();
if (!hasNotPermissionForAnyOf("ALL_FUNCTIONS", "ALL_FUNCTIONS_READ", matchPermission)) {
return;
@@ -34,4 +34,5 @@
<include file="parts/0012_add_merchantissuedrefund_payoutrefund_goodwillcredit_permissions.xml" relativeToChangelogFile="true"/>
<include file="parts/0013_remove_topics.xml" relativeToChangelogFile="true"/>
<include file="parts/0014_remove_unused_jobs.xml" relativeToChangelogFile="true"/>
<include file="parts/0015_add_business_date.xml" relativeToChangelogFile="true"/>
</databaseChangeLog>
@@ -0,0 +1,121 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<databaseChangeLog xmlns="http://www.liquibase.org/xml/ns/dbchangelog"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.liquibase.org/xml/ns/dbchangelog http://www.liquibase.org/xml/ns/dbchangelog/dbchangelog-4.1.xsd">
<changeSet author="fineract" id="1">
<createTable tableName="m_business_date">
<column autoIncrement="true" name="id" type="BIGINT">
<constraints nullable="false" primaryKey="true"/>
</column>
<column name="type" type="VARCHAR(100)">
<constraints unique="true" nullable="false"/>
</column>
<column name="date" type="DATE">
<constraints unique="false" nullable="false"/>
</column>
<column name="createdby_id" type="BIGINT"/>
<column name="created_date" type="DATETIME "/>
<column name="version" type="BIGINT">
<constraints nullable="false"/>
</column>
<column defaultValueComputed="NULL" name="lastmodifiedby_id" type="BIGINT"/>
<column defaultValueComputed="NULL" name="lastmodified_date" type="DATETIME"/>
</createTable>
</changeSet>
<changeSet id="2" author="fineract">
<insert tableName="c_configuration">
<column name="name" value="enable_business_date"/>
<column name="value"/>
<column name="date_value"/>
<column name="string_value"/>
<column name="enabled" valueBoolean="false"/>
<column name="is_trap_door" valueBoolean="false"/>
<column name="description" value="Whether the logical business date functionality is enabled in the system"/>
</insert>
<insert tableName="c_configuration">
<column name="name" value="enable_automatic_cob_date_adjustment"/>
<column name="value"/>
<column name="date_value"/>
<column name="string_value"/>
<column name="enabled" valueBoolean="true"/>
<column name="is_trap_door" valueBoolean="false"/>
<column name="description" value="Whether the cob date will be automatically recalculated based on the business date"/>
</insert>
</changeSet>
<changeSet id="3" author="fineract">
<insert tableName="m_permission">
<column name="grouping" value="organisation"/>
<column name="code" value="READ_BUSINESS_DATE"/>
<column name="entity_name" value="BUSINESS_DATE"/>
<column name="action_name" value="READ"/>
<column name="can_maker_checker" valueBoolean="false"/>
</insert>
<insert tableName="m_permission">
<column name="grouping" value="organisation"/>
<column name="code" value="UPDATE_BUSINESS_DATE"/>
<column name="entity_name" value="BUSINESS_DATE"/>
<column name="action_name" value="UPDATE"/>
<column name="can_maker_checker" valueBoolean="false"/>
</insert>
</changeSet>
<changeSet id="4" author="fineract">
<insert tableName="job">
<column name="name" value="Increase Business Date by 1 day"/>
<column name="display_name" value="Increase Business Date by 1 day"/>
<column name="cron_expression" value="0 0 0 1/1 * ? *"/>
<column name="create_time" valueDate="${current_datetime}"/>
<column name="task_priority" valueNumeric="99"/>
<column name="group_name"/>
<column name="previous_run_start_time"/>
<column name="job_key" value="Increase Business Date by 1 dayJobDetail1 _ DEFAULT"/>
<column name="initializing_errorlog"/>
<column name="is_active" valueBoolean="false"/>
<column name="currently_running" valueBoolean="false"/>
<column name="updates_allowed" valueBoolean="true"/>
<column name="scheduler_group" valueNumeric="0"/>
<column name="is_misfired" valueBoolean="false"/>
<column name="node_id" valueNumeric="1"/>
<column name="is_mismatched_job" valueBoolean="true"/>
</insert>
</changeSet>
<changeSet id="5" author="fineract">
<insert tableName="job">
<column name="name" value="Increase COB Date by 1 day"/>
<column name="display_name" value="Increase COB Date by 1 day"/>
<column name="cron_expression" value="0 0 0 1/1 * ? *"/>
<column name="create_time" valueDate="${current_datetime}"/>
<column name="task_priority" valueNumeric="98"/>
<column name="group_name"/>
<column name="previous_run_start_time"/>
<column name="job_key" value="Increase COB Date by 1 dayJobDetail1 _ DEFAULT"/>
<column name="initializing_errorlog"/>
<column name="is_active" valueBoolean="false"/>
<column name="currently_running" valueBoolean="false"/>
<column name="updates_allowed" valueBoolean="true"/>
<column name="scheduler_group" valueNumeric="0"/>
<column name="is_misfired" valueBoolean="false"/>
<column name="node_id" valueNumeric="1"/>
<column name="is_mismatched_job" valueBoolean="true"/>
</insert>
</changeSet>
</databaseChangeLog>
@@ -0,0 +1,163 @@
/**
* 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.businessdate.api;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoInteractions;
import java.io.IOException;
import java.util.List;
import javax.servlet.ServletException;
import javax.ws.rs.core.UriInfo;
import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.service.BusinessDateReadPlatformService;
import org.apache.fineract.infrastructure.core.api.ApiRequestParameterHelper;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.serialization.ApiRequestJsonSerializationSettings;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException;
import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext;
import org.apache.fineract.useradministration.domain.AppUser;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
class BusinessDateApiTest {
@Mock
private ApiRequestParameterHelper parameterHelper;
@Mock
private BusinessDateReadPlatformService readPlatformService;
@Mock
private UriInfo uriInfo;
@Mock
private PlatformSecurityContext securityContext;
@Mock
private DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer;
@Mock
private PortfolioCommandSourceWritePlatformService commandWritePlatformService;
@InjectMocks
private BusinessDateApiResource underTest;
private ApiRequestJsonSerializationSettings apiRequestJsonSerializationSettings;
@BeforeEach
void setUp() throws IOException {
apiRequestJsonSerializationSettings = new ApiRequestJsonSerializationSettings(false, null, false, false, false);
given(parameterHelper.process(Mockito.any())).willReturn(apiRequestJsonSerializationSettings);
}
@Test
void getBusinessDatesAPIHasPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
List<BusinessDateData> response = Mockito.mock(List.class);
given(readPlatformService.findAll()).willReturn(response);
// given
Mockito.doNothing().when(appUser).validateHasReadPermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
// when
underTest.getBusinessDates(uriInfo);
// then
verify(readPlatformService, Mockito.times(1)).findAll();
verify(jsonSerializer, Mockito.times(1)).serialize(apiRequestJsonSerializationSettings, response);
}
@Test
void getBusinessDatesAPIHasNoPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
// given
Mockito.doThrow(NoAuthorizationException.class).when(appUser).validateHasReadPermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
// when
assertThatThrownBy(() -> underTest.getBusinessDates(uriInfo)).isInstanceOf(NoAuthorizationException.class);
// then
verifyNoInteractions(readPlatformService);
}
@Test
void getBusinessDateByTypeAPIHasPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
BusinessDateData response = Mockito.mock(BusinessDateData.class);
given(readPlatformService.findByType("type")).willReturn(response);
// given
Mockito.doNothing().when(appUser).validateHasReadPermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
// when
underTest.getBusinessDate("type", uriInfo);
// then
verify(readPlatformService, Mockito.times(1)).findByType("type");
verify(jsonSerializer, Mockito.times(1)).serialize(apiRequestJsonSerializationSettings, response);
}
@Test
void getBusinessDateByTypeAPIHasNoPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
// given
Mockito.doThrow(NoAuthorizationException.class).when(appUser).validateHasReadPermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
// when
assertThatThrownBy(() -> underTest.getBusinessDate("type", uriInfo)).isInstanceOf(NoAuthorizationException.class);
// then
verifyNoInteractions(readPlatformService);
}
@Test
void postBusinessDateAPIHasPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
CommandProcessingResult response = Mockito.mock(CommandProcessingResult.class);
// given
Mockito.doNothing().when(appUser).validateHasUpdatePermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
given(commandWritePlatformService.logCommandSource(Mockito.any())).willReturn(response);
// when
underTest.updateBusinessDate("{}", uriInfo);
// then
verify(commandWritePlatformService, Mockito.times(1)).logCommandSource(Mockito.any());
verify(jsonSerializer, Mockito.times(1)).serialize(response);
}
@Test
void postBusinessDateAPIHasNoPermission() throws ServletException, IOException {
AppUser appUser = Mockito.mock(AppUser.class);
// given
Mockito.doThrow(NoAuthorizationException.class).when(appUser).validateHasUpdatePermission("BUSINESS_DATE");
given(securityContext.authenticatedUser()).willReturn(appUser);
// when
assertThatThrownBy(() -> underTest.updateBusinessDate("{}", uriInfo)).isInstanceOf(NoAuthorizationException.class);
// then
verifyNoInteractions(readPlatformService);
}
}
@@ -0,0 +1,63 @@
/**
* 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.businessdate.data;
import static org.junit.Assert.assertEquals;
import java.time.LocalDate;
import java.time.ZoneId;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.core.serialization.CommandProcessingResultJsonSerializer;
import org.apache.fineract.infrastructure.core.serialization.DefaultToApiJsonSerializer;
import org.apache.fineract.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson;
import org.apache.fineract.infrastructure.core.serialization.ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson;
import org.apache.fineract.infrastructure.core.serialization.GoogleGsonSerializerHelper;
import org.junit.Test;
public class BusinessDataSerialized {
@Test
public void serializeBusinessDateData() {
DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer = new DefaultToApiJsonSerializer<>(
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(),
new ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new GoogleGsonSerializerHelper());
LocalDate now = LocalDate.now(ZoneId.systemDefault());
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, now);
String result = jsonSerializer.serialize(businessDateData);
assertEquals("{\"description\":\"Business Date\",\"type\":\"BUSINESS_DATE\",\"date\":[" + now.getYear() + "," + now.getMonthValue()
+ "," + now.getDayOfMonth() + "]}", result);
}
@Test
public void serializeBusinessDateData_COB() {
DefaultToApiJsonSerializer<BusinessDateData> jsonSerializer = new DefaultToApiJsonSerializer<>(
new ExcludeNothingWithPrettyPrintingOffJsonSerializerGoogleGson(),
new ExcludeNothingWithPrettyPrintingOnJsonSerializerGoogleGson(), new CommandProcessingResultJsonSerializer(),
new GoogleGsonSerializerHelper());
LocalDate now = LocalDate.now(ZoneId.systemDefault());
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.COB_DATE, now);
String result = jsonSerializer.serialize(businessDateData);
assertEquals("{\"description\":\"Close of Business Date\",\"type\":\"COB_DATE\",\"date\":[" + now.getYear() + ","
+ now.getMonthValue() + "," + now.getDayOfMonth() + "]}", result);
}
}
@@ -0,0 +1,37 @@
/**
* 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.businessdate.data;
import static org.junit.Assert.assertEquals;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.junit.Test;
public class BusinessDataTypeTest {
@Test
public void typoCheck() {
for (BusinessDateType businessDateType : BusinessDateType.values()) {
switch (businessDateType) {
case BUSINESS_DATE -> assertEquals("Business Date", businessDateType.getDescription());
case COB_DATE -> assertEquals("Close of Business Date", businessDateType.getDescription());
}
}
}
}
@@ -0,0 +1,56 @@
/**
* 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.businessdate.mapper;
import static org.junit.Assert.assertEquals;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Collections;
import java.util.List;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.junit.Test;
import org.mapstruct.factory.Mappers;
public class BusinessDateMapperTest {
private BusinessDateMapper businessDateMapper = Mappers.getMapper(BusinessDateMapper.class);
@Test
public void testMapping() {
LocalDate now = LocalDate.now(ZoneId.systemDefault());
BusinessDate businessDate = BusinessDate.instance(BusinessDateType.BUSINESS_DATE, now);
BusinessDateData businessDateData = businessDateMapper.map(businessDate);
assertEquals(businessDate.getDate(), businessDateData.getDate());
assertEquals(businessDate.getType().getDescription(), businessDateData.getDescription());
assertEquals(businessDate.getType().getName(), businessDateData.getType());
}
@Test
public void testMappingList() {
LocalDate now = LocalDate.now(ZoneId.systemDefault());
BusinessDate businessDate = BusinessDate.instance(BusinessDateType.BUSINESS_DATE, now);
List<BusinessDateData> businessDateData = businessDateMapper.map(Collections.singletonList(businessDate));
assertEquals(businessDate.getDate(), businessDateData.get(0).getDate());
assertEquals(businessDate.getType().getDescription(), businessDateData.get(0).getDescription());
assertEquals(businessDate.getType().getName(), businessDateData.get(0).getType());
}
}
@@ -0,0 +1,96 @@
/**
* 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.businessdate.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.util.List;
import java.util.Optional;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateRepository;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.exception.BusinessDateNotFoundException;
import org.apache.fineract.infrastructure.businessdate.mapper.BusinessDateMapper;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class BusinessDateReadPlatformServiceTest {
@InjectMocks
private BusinessDateReadPlatformServiceImpl businessDateReadPlatformService;
@Mock
private BusinessDateRepository repository;
@Mock
private BusinessDateMapper mapper;
@Test
public void notFoundByTypeNonexistentType() {
BusinessDateNotFoundException businessDateNotFoundException = assertThrows(BusinessDateNotFoundException.class,
() -> businessDateReadPlatformService.findByType("invalid"));
assertEquals("Business date with type `invalid` does not exist.", businessDateNotFoundException.getDefaultUserMessage());
}
@Test
public void notFoundByTypeNotStoredInDB() {
BusinessDateNotFoundException businessDateNotFoundException = assertThrows(BusinessDateNotFoundException.class,
() -> businessDateReadPlatformService.findByType("BUSINESS_DATE"));
assertEquals("Business date with type `BUSINESS_DATE` does not found.", businessDateNotFoundException.getDefaultUserMessage());
}
@Test
public void findAll() {
List<BusinessDate> resultList = Mockito.mock(List.class);
given(repository.findAll()).willReturn(resultList);
businessDateReadPlatformService.findAll();
verify(repository, times(1)).findAll();
verify(mapper, times(1)).map(resultList);
}
@Test
public void findByCOBType() {
Optional<BusinessDate> result = Optional.of(Mockito.mock(BusinessDate.class));
given(repository.findByType(BusinessDateType.COB_DATE)).willReturn(result);
businessDateReadPlatformService.findByType("COB_DATE");
verify(repository, times(1)).findByType(BusinessDateType.COB_DATE);
verify(mapper, times(1)).map(result.get());
}
@Test
public void findByBusinessType() {
Optional<BusinessDate> result = Optional.of(Mockito.mock(BusinessDate.class));
given(repository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(result);
businessDateReadPlatformService.findByType("BUSINESS_DATE");
verify(repository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(mapper, times(1)).map(result.get());
}
}
@@ -0,0 +1,264 @@
/**
* 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.businessdate.service;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.BDDMockito.given;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Optional;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDate;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateRepository;
import org.apache.fineract.infrastructure.businessdate.domain.BusinessDateType;
import org.apache.fineract.infrastructure.businessdate.exception.BusinessDateActionException;
import org.apache.fineract.infrastructure.businessdate.validator.BusinessDateDataParserAndValidator;
import org.apache.fineract.infrastructure.configuration.domain.ConfigurationDomainService;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.data.CommandProcessingResult;
import org.apache.fineract.infrastructure.core.service.DateUtils;
import org.apache.fineract.infrastructure.jobs.exception.JobExecutionException;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
import org.mockito.junit.jupiter.MockitoSettings;
import org.mockito.quality.Strictness;
@ExtendWith(MockitoExtension.class)
@MockitoSettings(strictness = Strictness.LENIENT)
public class BusinessDateWritePlatformServiceTest {
@InjectMocks
private BusinessDateWritePlatformServiceImpl underTest;
@Mock
private BusinessDateDataParserAndValidator businessDateDataParserAndValidator;
@Mock
private BusinessDateRepository businessDateRepository;
@Mock
private ConfigurationDomainService configurationDomainService;
@Captor
private ArgumentCaptor<BusinessDate> businessDateArgumentCaptor;
@Test
public void businessDateIsNotEnabled() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE,
LocalDate.now(ZoneId.systemDefault()));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
BusinessDateActionException exception = assertThrows(BusinessDateActionException.class,
() -> underTest.updateBusinessDate(command));
assertEquals("Business date functionality is not enabled", exception.getDefaultUserMessage());
}
@Test
public void businessDateSetNew() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.empty();
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
LocalDate resultData = (LocalDate) result.getChanges().get("BUSINESS_DATE");
assertEquals(LocalDate.of(2022, 6, 13), resultData);
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(1)).save(businessDateArgumentCaptor.capture());
assertEquals(LocalDate.of(2022, 6, 13), businessDateArgumentCaptor.getValue().getDate());
assertEquals(BusinessDateType.BUSINESS_DATE, businessDateArgumentCaptor.getValue().getType());
}
@Test
public void cobDateSetNew() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.COB_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.empty();
given(businessDateRepository.findByType(BusinessDateType.COB_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
LocalDate resultData = (LocalDate) result.getChanges().get("COB_DATE");
assertEquals(LocalDate.of(2022, 6, 13), resultData);
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.COB_DATE);
verify(businessDateRepository, times(1)).save(businessDateArgumentCaptor.capture());
assertEquals(LocalDate.of(2022, 6, 13), businessDateArgumentCaptor.getValue().getDate());
assertEquals(BusinessDateType.COB_DATE, businessDateArgumentCaptor.getValue().getType());
}
@Test
public void businessDateSetModifyExistingWhenItWasAfter() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 11));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.of(BusinessDate.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 12)));
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
LocalDate resultData = (LocalDate) result.getChanges().get("BUSINESS_DATE");
assertEquals(LocalDate.of(2022, 6, 11), resultData);
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(1)).save(businessDateArgumentCaptor.capture());
assertEquals(LocalDate.of(2022, 6, 11), businessDateArgumentCaptor.getValue().getDate());
assertEquals(BusinessDateType.BUSINESS_DATE, businessDateArgumentCaptor.getValue().getType());
}
@Test
public void businessDateSetModifyExistingWhenItWasBefore() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.of(BusinessDate.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 12)));
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
LocalDate resultData = (LocalDate) result.getChanges().get("BUSINESS_DATE");
assertEquals(LocalDate.of(2022, 6, 13), resultData);
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(1)).save(businessDateArgumentCaptor.capture());
assertEquals(LocalDate.of(2022, 6, 13), businessDateArgumentCaptor.getValue().getDate());
assertEquals(BusinessDateType.BUSINESS_DATE, businessDateArgumentCaptor.getValue().getType());
}
@Test
public void businessDateSetModifyExistingButNoChanges() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.FALSE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.of(BusinessDate.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13)));
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
assertNull(result.getChanges());
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(0)).save(businessDateArgumentCaptor.capture());
}
@Test
public void cobDateSetNewAutomatically() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.TRUE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newEntity = Optional.empty();
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
LocalDate businessDate = (LocalDate) result.getChanges().get("BUSINESS_DATE");
assertEquals(LocalDate.of(2022, 6, 13), businessDate);
LocalDate cobDate = (LocalDate) result.getChanges().get("COB_DATE");
assertEquals(LocalDate.of(2022, 6, 12), cobDate);
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(1)).findByType(BusinessDateType.COB_DATE);
verify(businessDateRepository, times(2)).save(businessDateArgumentCaptor.capture());
assertEquals(LocalDate.of(2022, 6, 13), businessDateArgumentCaptor.getAllValues().get(0).getDate());
assertEquals(BusinessDateType.BUSINESS_DATE, businessDateArgumentCaptor.getAllValues().get(0).getType());
assertEquals(LocalDate.of(2022, 6, 12), businessDateArgumentCaptor.getAllValues().get(1).getDate());
assertEquals(BusinessDateType.COB_DATE, businessDateArgumentCaptor.getAllValues().get(1).getType());
}
@Test
public void businessDateAndCobDateSetModifyExistingButNoChanges() {
JsonCommand command = JsonCommand.from("");
BusinessDateData businessDateData = BusinessDateData.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13));
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.TRUE);
given(businessDateDataParserAndValidator.validateAndParseUpdate(command)).willReturn(businessDateData);
Optional<BusinessDate> newBusinessEntity = Optional
.of(BusinessDate.instance(BusinessDateType.BUSINESS_DATE, LocalDate.of(2022, 6, 13)));
Optional<BusinessDate> newCOBEntity = Optional.of(BusinessDate.instance(BusinessDateType.COB_DATE, LocalDate.of(2022, 6, 12)));
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newBusinessEntity);
given(businessDateRepository.findByType(BusinessDateType.COB_DATE)).willReturn(newCOBEntity);
CommandProcessingResult result = underTest.updateBusinessDate(command);
assertNull(result.getChanges());
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).findByType(BusinessDateType.BUSINESS_DATE);
verify(businessDateRepository, times(1)).findByType(BusinessDateType.COB_DATE);
verify(businessDateRepository, times(0)).save(Mockito.any());
}
@Test
public void businessDateIsNotEnabledTriggeredByJob() {
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.FALSE);
assertThrows(JobExecutionException.class, () -> underTest.increaseBusinessDateByOneDay());
}
@Test
public void businessDateSetNewTriggeredByJob() throws JobExecutionException {
LocalDate localDate = DateUtils.getLocalDateOfTenant();
LocalDate localDatePlus1 = localDate.plusDays(1);
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.TRUE);
Optional<BusinessDate> newEntity = Optional.empty();
given(businessDateRepository.findByType(BusinessDateType.BUSINESS_DATE)).willReturn(newEntity);
underTest.increaseBusinessDateByOneDay();
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(2)).save(businessDateArgumentCaptor.capture());
assertEquals(localDatePlus1, businessDateArgumentCaptor.getAllValues().get(0).getDate());
assertEquals(BusinessDateType.BUSINESS_DATE, businessDateArgumentCaptor.getAllValues().get(0).getType());
assertEquals(localDate, businessDateArgumentCaptor.getAllValues().get(1).getDate());
assertEquals(BusinessDateType.COB_DATE, businessDateArgumentCaptor.getAllValues().get(1).getType());
}
@Test
public void cobDateModifyExistingTriggeredByJob() throws JobExecutionException {
Optional<BusinessDate> newCOBEntity = Optional.of(BusinessDate.instance(BusinessDateType.COB_DATE, LocalDate.of(2022, 6, 12)));
given(businessDateRepository.findByType(BusinessDateType.COB_DATE)).willReturn(newCOBEntity);
LocalDate localDate = LocalDate.of(2022, 6, 12).plusDays(1);
given(configurationDomainService.isBusinessDateEnabled()).willReturn(Boolean.TRUE);
given(configurationDomainService.isCOBDateAdjustmentEnabled()).willReturn(Boolean.TRUE);
underTest.increaseCOBDateByOneDay();
verify(configurationDomainService, times(1)).isBusinessDateEnabled();
verify(configurationDomainService, times(1)).isCOBDateAdjustmentEnabled();
verify(businessDateRepository, times(1)).save(businessDateArgumentCaptor.capture());
assertEquals(localDate, businessDateArgumentCaptor.getValue().getDate());
}
}
@@ -0,0 +1,120 @@
/**
* 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.businessdate.validator;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThrows;
import java.time.LocalDate;
import org.apache.fineract.infrastructure.businessdate.data.BusinessDateData;
import org.apache.fineract.infrastructure.core.api.JsonCommand;
import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException;
import org.apache.fineract.infrastructure.core.serialization.FromJsonHelper;
import org.junit.Test;
public class BusinessDateValidatorTest {
private BusinessDateDataParserAndValidator businessDateDataParserAndValidator = new BusinessDateDataParserAndValidator(
new FromJsonHelper());
@Test
public void validateAndParseUpdateWithEmptyRequest() {
String json = "{}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals(
"PlatformApiDataValidationException{errors=[The parameter `type` is mandatory., The parameter `locale` is mandatory., The parameter `dateFormat` is mandatory., The parameter `date` is mandatory.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithBlankFieldsInRequest() {
String json = "{\"type\":\"\", \"locale\":\"\",\"dateFormat\":\"\",\"date\":\"\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals(
"PlatformApiDataValidationException{errors=[The parameter `type` is mandatory., The parameter `locale` is mandatory., The parameter `dateFormat` is mandatory., The parameter `date` is mandatory.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithInvalidLocale() {
String json = "{\"type\":\"BUSINESS_DATE\", \"locale\":\"invalid\",\"dateFormat\":\"yyyy-MM-dd\",\"date\":\"2022-06-11\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals("PlatformApiDataValidationException{errors=[The parameter `locale` has an invalid language value: `invalid`.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithInvalidBusinessType() {
String json = "{\"type\":\"invalid\", \"locale\":\"hu\",\"dateFormat\":\"yyyy-MM-dd\",\"date\":\"2022-06-11\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals("PlatformApiDataValidationException{errors=[Failed data validation due to: Invalid Business Type value: `invalid`.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithInvalidDateFormat() {
String json = "{\"type\":\"BUSINESS_DATE\", \"locale\":\"hu\",\"dateFormat\":\"y2yyy-MM-dd\",\"date\":\"2022-06-11\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals(
"PlatformApiDataValidationException{errors=[The parameter `date` (value=2022-06-11) is invalid based on the dateFormat: `y2yyy-MM-dd` and locale: `hu` provided.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithInvalidDate() {
String json = "{\"type\":\"BUSINESS_DATE\", \"locale\":\"hu\",\"dateFormat\":\"yyyy-MM-dd\",\"date\":\"2y22-06-11\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals(
"PlatformApiDataValidationException{errors=[The parameter `date` (value=2y22-06-11) is invalid based on the dateFormat: `yyyy-MM-dd` and locale: `hu` provided.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithWrongDate() {
String json = "{\"type\":\"BUSINESS_DATE\", \"locale\":\"hu\",\"dateFormat\":\"yyyy-MM-dd\",\"date\":\"11-06-2022\"}";
JsonCommand command = JsonCommand.from(json);
PlatformApiDataValidationException exception = assertThrows(PlatformApiDataValidationException.class,
() -> businessDateDataParserAndValidator.validateAndParseUpdate(command));
assertEquals(
"PlatformApiDataValidationException{errors=[The parameter `date` (value=11-06-2022) is invalid based on the dateFormat: `yyyy-MM-dd` and locale: `hu` provided.]}",
exception.toString());
}
@Test
public void validateAndParseUpdateWithRighDate() {
String json = "{\"type\":\"COB_DATE\", \"locale\":\"hu\",\"dateFormat\":\"yyyy-MM-dd\",\"date\":\"2022-06-11\"}";
JsonCommand command = JsonCommand.from(json);
BusinessDateData result = businessDateDataParserAndValidator.validateAndParseUpdate(command);
assertEquals("COB_DATE", result.getType());
assertEquals("Close of Business Date", result.getDescription());
assertEquals(LocalDate.of(2022, 6, 11), result.getDate());
}
}
@@ -22,14 +22,17 @@ import static org.awaitility.Awaitility.await;
import static org.junit.jupiter.api.Assertions.assertEquals;
import io.restassured.builder.RequestSpecBuilder;
import io.restassured.builder.ResponseSpecBuilder;
import io.restassured.http.ContentType;
import io.restassured.specification.RequestSpecification;
import io.restassured.specification.ResponseSpecification;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import org.apache.fineract.infrastructure.jobs.service.JobName;
import org.apache.fineract.integrationtests.common.GlobalConfigurationHelper;
import org.apache.fineract.integrationtests.common.SchedulerJobHelper;
import org.apache.fineract.integrationtests.common.Utils;
import org.junit.jupiter.api.AfterEach;
@@ -134,6 +137,8 @@ public class SchedulerJobsTest {
@Test
public void testTriggeringManualExecutionOfAllSchedulerJobs() {
ResponseSpecification responseSpec = new ResponseSpecBuilder().expectStatusCode(200).build();
GlobalConfigurationHelper.updateIsBusinessDateEnabled(requestSpec, responseSpec, Boolean.TRUE);
for (String jobName : schedulerJobHelper.getAllSchedulerJobNames()) {
schedulerJobHelper.executeAndAwaitJob(jobName);
}
@@ -99,8 +99,8 @@ public class GlobalConfigurationHelper {
ArrayList<HashMap> actualGlobalConfigurations = getAllGlobalConfigurations(requestSpec, responseSpec);
// There are currently 37 global configurations.
Assertions.assertEquals(38, expectedGlobalConfigurations.size());
Assertions.assertEquals(38, actualGlobalConfigurations.size());
Assertions.assertEquals(40, expectedGlobalConfigurations.size());
Assertions.assertEquals(40, actualGlobalConfigurations.size());
for (int i = 0; i < expectedGlobalConfigurations.size(); i++) {
@@ -440,6 +440,22 @@ public class GlobalConfigurationHelper {
isPrincipalCompoundingDisabled.put("trapDoor", false);
defaults.add(isPrincipalCompoundingDisabled);
HashMap<String, Object> isBusinessDateEnabled = new HashMap<>();
isBusinessDateEnabled.put("id", 44);
isBusinessDateEnabled.put("name", "enable_business_date");
isBusinessDateEnabled.put("value", 0);
isBusinessDateEnabled.put("enabled", true);
isBusinessDateEnabled.put("trapDoor", false);
defaults.add(isBusinessDateEnabled);
HashMap<String, Object> isAutomaticCOBDateAdjustmentEnabled = new HashMap<>();
isAutomaticCOBDateAdjustmentEnabled.put("id", 45);
isAutomaticCOBDateAdjustmentEnabled.put("name", "enable_automatic_cob_date_adjustment");
isAutomaticCOBDateAdjustmentEnabled.put("value", 0);
isAutomaticCOBDateAdjustmentEnabled.put("enabled", true);
isAutomaticCOBDateAdjustmentEnabled.put("trapDoor", false);
defaults.add(isAutomaticCOBDateAdjustmentEnabled);
return defaults;
}
@@ -530,4 +546,9 @@ public class GlobalConfigurationHelper {
return new Gson().toJson(map);
}
public static Integer updateIsBusinessDateEnabled(final RequestSpecification requestSpec, final ResponseSpecification responseSpec,
final boolean enabled) {
long configId = 44;
return updateEnabledFlagForGlobalConfiguration(requestSpec, responseSpec, configId, enabled);
}
}