From d857d8b47a2f283849c59eb086f98a9be95512a6 Mon Sep 17 00:00:00 2001 From: Nazeer Hussain Shaik Date: Fri, 22 Sep 2017 12:37:17 +0530 Subject: [PATCH] survey enhancement --- .../spm/api/ScorecardApiResource.java | 59 ++++--- .../fineract/spm/api/SpmApiResource.java | 60 +++++--- .../fineract/spm/data/ScorecardData.java | 78 +++++++--- .../fineract/spm/data/ScorecardValue.java | 23 ++- .../apache/fineract/spm/domain/Survey.java | 14 +- .../fineract/spm/domain/SurveyValidator.java | 95 ++++++++++++ .../service/ScorecardReadPlatformService.java | 33 ++++ .../ScorecardReadPlatformServiceImpl.java | 144 ++++++++++++++++++ .../fineract/spm/service/SpmService.java | 106 ++++++++----- .../fineract/spm/util/ScorecardMapper.java | 35 +---- .../fineract/spm/util/SurveyApiConstants.java | 44 ++++++ .../fineract/spm/util/SurveyMapper.java | 3 +- .../resources/META-INF/spring/spmContext.xml | 2 +- 13 files changed, 548 insertions(+), 148 deletions(-) create mode 100644 fineract-provider/src/main/java/org/apache/fineract/spm/domain/SurveyValidator.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformService.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformServiceImpl.java create mode 100644 fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyApiConstants.java diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/api/ScorecardApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/spm/api/ScorecardApiResource.java index 84987daa76e..e2927d5d830 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/api/ScorecardApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/api/ScorecardApiResource.java @@ -18,7 +18,6 @@ */ package org.apache.fineract.spm.api; -import java.util.Collections; import java.util.List; import javax.ws.rs.Consumes; @@ -33,9 +32,8 @@ import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.portfolio.client.domain.ClientRepositoryWrapper; import org.apache.fineract.spm.data.ScorecardData; -import org.apache.fineract.spm.domain.Scorecard; import org.apache.fineract.spm.domain.Survey; -import org.apache.fineract.spm.exception.SurveyNotFoundException; +import org.apache.fineract.spm.service.ScorecardReadPlatformService; import org.apache.fineract.spm.service.ScorecardService; import org.apache.fineract.spm.service.SpmService; import org.apache.fineract.spm.util.ScorecardMapper; @@ -45,7 +43,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -@Path("/surveys/{surveyId}/scorecards") +@Path("/surveys/scorecards") @Component @Scope("singleton") public class ScorecardApiResource { @@ -54,68 +52,63 @@ public class ScorecardApiResource { private final SpmService spmService; private final ScorecardService scorecardService; private final ClientRepositoryWrapper clientRepositoryWrapper; + private final ScorecardReadPlatformService scorecardReadPlatformService; @Autowired public ScorecardApiResource(final PlatformSecurityContext securityContext, final SpmService spmService, - final ScorecardService scorecardService, final ClientRepositoryWrapper clientRepositoryWrapper) { - super(); + final ScorecardService scorecardService, final ClientRepositoryWrapper clientRepositoryWrapper, + final ScorecardReadPlatformService scorecardReadPlatformService) { this.securityContext = securityContext; this.spmService = spmService; this.scorecardService = scorecardService; this.clientRepositoryWrapper = clientRepositoryWrapper; + this.scorecardReadPlatformService = scorecardReadPlatformService; } @GET + @Path("{surveyId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Transactional public List findBySurvey(@PathParam("surveyId") final Long surveyId) { this.securityContext.authenticatedUser(); - - final Survey survey = findSurvey(surveyId); - - final List scorecards = this.scorecardService.findBySurvey(survey); - - if (scorecards != null) { - return ScorecardMapper.map(scorecards); - } - - return Collections.EMPTY_LIST; + this.spmService.findById(surveyId); + return (List) this.scorecardReadPlatformService.retrieveScorecardBySurvey(surveyId); } @POST + @Path("{surveyId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Transactional public void createScorecard(@PathParam("surveyId") final Long surveyId, final ScorecardData scorecardData) { final AppUser appUser = this.securityContext.authenticatedUser(); - final Survey survey = findSurvey(surveyId); + final Survey survey = this.spmService.findById(surveyId); final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(scorecardData.getClientId()); this.scorecardService.createScorecard(ScorecardMapper.map(scorecardData, survey, appUser, client)); } - @Path("/clients/{clientId}") @GET + @Path("{surveyId}/clients/{clientId}") @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Transactional - public List findBySurveyClient(@PathParam("surveyId") final Long surveyId, - @PathParam("clientId") final Long clientId) { + public List findBySurveyAndClient(@PathParam("surveyId") final Long surveyId, @PathParam("clientId") final Long clientId) { this.securityContext.authenticatedUser(); - final Survey survey = findSurvey(surveyId); - final Client client = this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); - final List scorecards = this.scorecardService.findBySurveyAndClient(survey, client); - if (scorecards != null) { - return ScorecardMapper.map(scorecards); - } - return Collections.EMPTY_LIST; + this.spmService.findById(surveyId); + this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + return (List) this.scorecardReadPlatformService.retrieveScorecardBySurveyAndClient(surveyId, clientId); + } - private Survey findSurvey(final Long surveyId) { - final Survey survey = this.spmService.findById(surveyId); - if (survey == null) { - throw new SurveyNotFoundException(surveyId); - } - return survey; + @GET + @Path("clients/{clientId}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Transactional + public List findByClient(@PathParam("clientId") final Long clientId) { + this.securityContext.authenticatedUser(); + this.clientRepositoryWrapper.findOneWithNotFoundDetection(clientId); + return (List) this.scorecardReadPlatformService.retrieveScorecardByClient(clientId); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/api/SpmApiResource.java b/fineract-provider/src/main/java/org/apache/fineract/spm/api/SpmApiResource.java index 8da5c154a61..46afed0edba 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/api/SpmApiResource.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/api/SpmApiResource.java @@ -18,10 +18,23 @@ */ package org.apache.fineract.spm.api; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; + import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.spm.data.SurveyData; import org.apache.fineract.spm.domain.Survey; -import org.apache.fineract.spm.exception.SurveyNotFoundException; import org.apache.fineract.spm.service.SpmService; import org.apache.fineract.spm.util.SurveyMapper; import org.springframework.beans.factory.annotation.Autowired; @@ -29,10 +42,7 @@ import org.springframework.stereotype.Component; import org.springframework.transaction.annotation.Transactional; -import javax.ws.rs.*; -import javax.ws.rs.core.MediaType; -import java.util.ArrayList; -import java.util.List; +import com.google.gson.Gson; @Path("/surveys") @Component @@ -43,8 +53,7 @@ public class SpmApiResource { private final SpmService spmService; @Autowired - public SpmApiResource(final PlatformSecurityContext securityContext, - final SpmService spmService) { + public SpmApiResource(final PlatformSecurityContext securityContext, final SpmService spmService) { this.securityContext = securityContext; this.spmService = spmService; } @@ -55,17 +64,13 @@ public SpmApiResource(final PlatformSecurityContext securityContext, @Transactional public List fetchActiveSurveys() { this.securityContext.authenticatedUser(); - final List result = new ArrayList<>(); - final List surveys = this.spmService.fetchValidSurveys(); - if (surveys != null) { for (final Survey survey : surveys) { result.add(SurveyMapper.map(survey)); } } - return result; } @@ -76,13 +81,7 @@ public List fetchActiveSurveys() { @Transactional public SurveyData findSurvey(@PathParam("id") final Long id) { this.securityContext.authenticatedUser(); - final Survey survey = this.spmService.findById(id); - - if (survey == null) { - throw new SurveyNotFoundException(id); - } - return SurveyMapper.map(survey); } @@ -90,12 +89,25 @@ public SurveyData findSurvey(@PathParam("id") final Long id) { @Consumes({ MediaType.APPLICATION_JSON }) @Produces({ MediaType.APPLICATION_JSON }) @Transactional - public void createSurvey(final SurveyData surveyData) { + public String createSurvey(final SurveyData surveyData) { this.securityContext.authenticatedUser(); + final Survey survey = SurveyMapper.map(surveyData, new Survey()); + this.spmService.createSurvey(survey); + return getResponse(survey.getId()); - final Survey survey = SurveyMapper.map(surveyData); + } - this.spmService.createSurvey(survey); + @PUT + @Path("/{id}") + @Consumes({ MediaType.APPLICATION_JSON }) + @Produces({ MediaType.APPLICATION_JSON }) + @Transactional + public String editSurvey(@PathParam("id") final Long id, final SurveyData surveyData) { + this.securityContext.authenticatedUser(); + final Survey surveyToUpdate = this.spmService.findById(id); + final Survey survey = SurveyMapper.map(surveyData, surveyToUpdate); + this.spmService.updateSurvey(survey); + return getResponse(survey.getId()); } @DELETE @@ -105,7 +117,13 @@ public void createSurvey(final SurveyData surveyData) { @Transactional public void deactivateSurvey(@PathParam("id") final Long id) { this.securityContext.authenticatedUser(); - this.spmService.deactivateSurvey(id); } + + private String getResponse(Long id) { + Gson gson = new Gson(); + HashMap response = new HashMap<>(); + response.put("resourceId", id); + return gson.toJson(response); + } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardData.java b/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardData.java index b19b79e3a5a..6c359933c1b 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardData.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardData.java @@ -18,58 +18,96 @@ */ package org.apache.fineract.spm.data; -import java.util.Date; +import java.util.ArrayList; import java.util.List; public class ScorecardData { + private Long id; private Long userId; + private String username; private Long clientId; - private Date createdOn; + private Long surveyId; + private String surveyName; private List scorecardValues; public ScorecardData() { super(); } - public ScorecardData(final Long userId, final Long clientId, final Date createdOn, - final List scorecardValues) { - super(); + private ScorecardData(final Long id, final Long userId, final String username, final Long surveyId, final String surveyName, + final Long clientId) { + this.id = id; this.userId = userId; this.clientId = clientId; - this.createdOn = createdOn; - this.scorecardValues = scorecardValues; + this.scorecardValues = new ArrayList<>(); + this.surveyId = surveyId; + this.surveyName = surveyName; + this.username = username; + } + + public static ScorecardData instance(final Long id, final Long userId, final String username, final Long surveyId, + final String surveyName, final Long clientId) { + return new ScorecardData(id, userId, username, surveyId, surveyName, clientId); } public Long getUserId() { return userId; } + public Long getClientId() { + return clientId; + } + + public List getScorecardValues() { + return scorecardValues; + } + + public void setScorecardValues(List scorecardValues) { + if (this.scorecardValues == null) { + this.scorecardValues = new ArrayList<>(); + } + this.scorecardValues.addAll(scorecardValues); + } + + public String getUsername() { + return this.username; + } + + public Long getSurveyId() { + return this.surveyId; + } + + public String getSurveyName() { + return this.surveyName; + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + public void setUserId(Long userId) { this.userId = userId; } - public Long getClientId() { - return clientId; + public void setUsername(String username) { + this.username = username; } public void setClientId(Long clientId) { this.clientId = clientId; } - public Date getCreatedOn() { - return createdOn; - } - - public void setCreatedOn(Date createdOn) { - this.createdOn = createdOn; + public void setSurveyId(Long surveyId) { + this.surveyId = surveyId; } - public List getScorecardValues() { - return scorecardValues; + public void setSurveyName(String surveyName) { + this.surveyName = surveyName; } - public void setScorecardValues(List scorecardValues) { - this.scorecardValues = scorecardValues; - } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardValue.java b/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardValue.java index 9f22c2ae269..c45b19bff7d 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardValue.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/data/ScorecardValue.java @@ -18,21 +18,28 @@ */ package org.apache.fineract.spm.data; +import java.util.Date; + public class ScorecardValue { private Long questionId; private Long responseId; private Integer value; + private Date createdOn; public ScorecardValue() { super(); } - public ScorecardValue(final Long questionId, final Long responseId, final Integer value) { - super(); + private ScorecardValue(final Long questionId, final Long responseId, final Integer value, final Date createdOn) { this.questionId = questionId; this.responseId = responseId; this.value = value; + this.createdOn = createdOn; + } + + public static ScorecardValue instance(final Long questionId, final Long responseId, final Integer value, final Date createdOn) { + return new ScorecardValue(questionId, responseId, value, createdOn); } public Long getQuestionId() { @@ -58,4 +65,16 @@ public Integer getValue() { public void setValue(Integer value) { this.value = value; } + + + public Date getCreatedOn() { + return this.createdOn; + } + + + public void setCreatedOn(Date createdOn) { + this.createdOn = createdOn; + } + + } diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/domain/Survey.java b/fineract-provider/src/main/java/org/apache/fineract/spm/domain/Survey.java index bd6890595e3..ad4f96170b3 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/domain/Survey.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/domain/Survey.java @@ -21,6 +21,8 @@ import org.apache.fineract.infrastructure.core.domain.AbstractPersistableCustom; import javax.persistence.*; + +import java.util.ArrayList; import java.util.Date; import java.util.List; @@ -28,11 +30,11 @@ @Table(name = "m_surveys") public class Survey extends AbstractPersistableCustom { - @OneToMany(mappedBy = "survey", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @OneToMany(mappedBy = "survey", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true) @OrderBy("sequenceNo") private List components; - @OneToMany(mappedBy = "survey", fetch = FetchType.EAGER, cascade = CascadeType.ALL) + @OneToMany(mappedBy = "survey", fetch = FetchType.EAGER, cascade = CascadeType.ALL, orphanRemoval=true) @OrderBy("sequenceNo") private List questions; @@ -73,7 +75,13 @@ public List getQuestions() { } public void setQuestions(List questions) { - this.questions = questions; + if(this.questions != null){ + this.questions.clear();; + }else{ + this.questions = new ArrayList<>(); + } + + this.questions.addAll(questions); } public String getKey() { diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/domain/SurveyValidator.java b/fineract-provider/src/main/java/org/apache/fineract/spm/domain/SurveyValidator.java new file mode 100644 index 00000000000..a3e2ee63b4e --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/domain/SurveyValidator.java @@ -0,0 +1,95 @@ +/** + * 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.spm.domain; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.fineract.infrastructure.core.data.ApiParameterError; +import org.apache.fineract.infrastructure.core.data.DataValidatorBuilder; +import org.apache.fineract.infrastructure.core.exception.PlatformApiDataValidationException; +import org.apache.fineract.spm.util.SurveyApiConstants; +import org.springframework.stereotype.Component; + +@Component +public class SurveyValidator { + + public void validate(final Survey survey) { + final List dataValidationErrors = new ArrayList<>(); + + final DataValidatorBuilder baseDataValidator = new DataValidatorBuilder(dataValidationErrors) + .resource(SurveyApiConstants.SURVEY_RESOURCE_NAME); + + baseDataValidator.reset().parameter(SurveyApiConstants.keyParamName).value(survey.getKey()).notNull().notBlank() + .notExceedingLengthOf(SurveyApiConstants.maxKeyLength); + + baseDataValidator.reset().parameter(SurveyApiConstants.nameParamName).value(survey.getName()).notNull().notBlank() + .notExceedingLengthOf(SurveyApiConstants.maxNameLength); + + baseDataValidator.reset().parameter(SurveyApiConstants.countryCodeParamName).value(survey.getCountryCode()).notNull().notBlank() + .notExceedingLengthOf(SurveyApiConstants.maxCountryCodeLength); + baseDataValidator.reset().parameter(SurveyApiConstants.descriptionParamName).value(survey.getDescription()).ignoreIfNull() + .notExceedingLengthOf(SurveyApiConstants.maxDescriptionLength); + List questions = survey.getQuestions(); + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName).value(questions).notNull(); + validateQuestions(baseDataValidator, questions); + throwExceptionIfValidationWarningsExist(dataValidationErrors); + + } + + private void validateQuestions(final DataValidatorBuilder baseDataValidator, List questions) { + if (questions != null) { + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.lengthParamName) + .value(questions.toArray()).arrayNotEmpty(); + for (Question question : questions) { + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.keyParamName) + .value(question.getKey()).notNull().notExceedingLengthOf(SurveyApiConstants.maxKeyLength); + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.textParamName) + .value(question.getText()).notNull().notExceedingLengthOf(SurveyApiConstants.maxTextLength); + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.descriptionParamName) + .value(question.getDescription()).ignoreIfNull().notExceedingLengthOf(SurveyApiConstants.maxDescriptionLength); + validateOptions(baseDataValidator, question); + + } + } + } + + private void validateOptions(final DataValidatorBuilder baseDataValidator, Question question) { + List responses = question.getResponses(); + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.optionsParamName) + .value(responses).notNull(); + if (responses != null) { + baseDataValidator.reset().parameter(SurveyApiConstants.questionParamName + "." + SurveyApiConstants.optionsParamName) + .value(responses.toArray()).arrayNotEmpty(); + for (Response response : responses) { + baseDataValidator.reset().parameter(SurveyApiConstants.optionsParamName + "." + SurveyApiConstants.textParamName) + .value(response.getText()).notNull().notExceedingLengthOf(SurveyApiConstants.maxTextLength); + baseDataValidator.reset().parameter(SurveyApiConstants.optionsParamName + "." + SurveyApiConstants.valueParamName) + .value(response.getValue()).notNull().notGreaterThanMax(SurveyApiConstants.maxOptionsValue); + } + } + } + + private void throwExceptionIfValidationWarningsExist(final List dataValidationErrors) { + if (!dataValidationErrors.isEmpty()) { + throw new PlatformApiDataValidationException(dataValidationErrors); + } + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformService.java b/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformService.java new file mode 100644 index 00000000000..78d74dca99c --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformService.java @@ -0,0 +1,33 @@ +/** + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ +package org.apache.fineract.spm.service; + +import java.util.Collection; + +import org.apache.fineract.spm.data.ScorecardData; + + +public interface ScorecardReadPlatformService { + + Collection retrieveScorecardByClient(final Long clientId); + + Collection retrieveScorecardBySurveyAndClient(final Long surveyId,final Long clientId); + + Collection retrieveScorecardBySurvey(final Long surveyId); +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformServiceImpl.java b/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformServiceImpl.java new file mode 100644 index 00000000000..2859a3cb863 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/service/ScorecardReadPlatformServiceImpl.java @@ -0,0 +1,144 @@ +/** + * 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.spm.service; + +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Collection; +import java.util.List; + +import org.apache.fineract.infrastructure.core.domain.JdbcSupport; +import org.apache.fineract.infrastructure.core.service.RoutingDataSource; +import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; +import org.apache.fineract.spm.data.ScorecardData; +import org.apache.fineract.spm.data.ScorecardValue; +import org.joda.time.LocalDate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.RowMapper; +import org.springframework.stereotype.Service; + +@Service +public class ScorecardReadPlatformServiceImpl implements ScorecardReadPlatformService { + + private final JdbcTemplate jdbcTemplate; + private final PlatformSecurityContext context; + + @Autowired + public ScorecardReadPlatformServiceImpl(final PlatformSecurityContext context, final RoutingDataSource dataSource) { + this.context = context; + this.jdbcTemplate = new JdbcTemplate(dataSource); + } + + private static final class ScorecardMapper implements RowMapper { + + public String schema() { + StringBuilder sb = new StringBuilder(50); + sb.append(" sc.id as id, sc.survey_id as surveyId, s.a_name as surveyName, "); + sb.append(" sc.client_id as clientId,"); + sb.append(" sc.user_id as userId, user.username as username "); + sb.append(" from m_survey_scorecards sc "); + sb.append(" left join m_surveys s ON s.id = sc.survey_id "); + sb.append(" left join m_appuser user ON user.id = sc.user_id "); + + return sb.toString(); + } + + @Override + public ScorecardData mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long id = rs.getLong("id"); + final Long surveyId = rs.getLong("surveyId"); + final String surveyName = rs.getString("surveyName"); + final Long clientId = rs.getLong("clientId"); + final Long userId = rs.getLong("userId"); + final String username = rs.getString("username"); + + return ScorecardData.instance(id, userId, username, surveyId, surveyName, clientId); + } + } + + private static final class ScorecardValueMapper implements RowMapper { + + public String schema() { + StringBuilder sb = new StringBuilder(50); + sb.append(" sc.question_id as questionId, sc.response_id as responseId, "); + sb.append(" sc.created_on as createdOn, sc.a_value as value "); + sb.append(" from m_survey_scorecards sc "); + sb.append(" where sc.survey_id = ? and sc.client_id = ? "); + + return sb.toString(); + } + + @Override + public ScorecardValue mapRow(final ResultSet rs, @SuppressWarnings("unused") final int rowNum) throws SQLException { + + final Long questionId = rs.getLong("questionId"); + final Long responseId = rs.getLong("responseId"); + final LocalDate createdOn = JdbcSupport.getLocalDate(rs, "createdOn"); + final Integer value = rs.getInt("value"); + + return ScorecardValue.instance(questionId, responseId, value, createdOn.toDate()); + } + } + + List getScorecardValueBySurveyAndClient(final Long surveyId, final Long clientId) { + ScorecardValueMapper scvm = new ScorecardValueMapper(); + String sql = "select " + scvm.schema(); + return this.jdbcTemplate.query(sql, scvm, new Object[] { surveyId, clientId }); + } + + Collection updateScorecardValues(Collection scorecard) { + for (ScorecardData scorecardData : scorecard) { + scorecardData.setScorecardValues(getScorecardValueBySurveyAndClient(scorecardData.getSurveyId(), scorecardData.getClientId())); + } + return scorecard; + } + + @Override + public Collection retrieveScorecardBySurvey(Long surveyId) { + this.context.authenticatedUser(); + ScorecardMapper scm = new ScorecardMapper(); + String sql = "select " + scm.schema() + " where sc.survey_id = ? " + " group by sc.survey_id, sc.client_id "; + Collection scorecardDatas = this.jdbcTemplate.query(sql, scm, new Object[] { surveyId }); + updateScorecardValues(scorecardDatas); + return scorecardDatas; + } + + @Override + public Collection retrieveScorecardByClient(Long clientId) { + this.context.authenticatedUser(); + ScorecardMapper scm = new ScorecardMapper(); + String sql = "select " + scm.schema() + " where sc.client_id = ? " + " group by sc.survey_id, sc.client_id "; + Collection scorecardDatas = this.jdbcTemplate.query(sql, scm, new Object[] { clientId }); + updateScorecardValues(scorecardDatas); + return scorecardDatas; + } + + @Override + public Collection retrieveScorecardBySurveyAndClient(Long surveyId, Long clientId) { + this.context.authenticatedUser(); + ScorecardMapper scm = new ScorecardMapper(); + String sql = "select " + scm.schema() + " where sc.survey_id = ? and sc.client_id = ? " + " group by sc.survey_id, sc.client_id "; + Collection scorecardDatas = this.jdbcTemplate.query(sql, scm, new Object[] { surveyId, clientId }); + updateScorecardValues(scorecardDatas); + return scorecardDatas; + } + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/service/SpmService.java b/fineract-provider/src/main/java/org/apache/fineract/spm/service/SpmService.java index 424bdafbd59..52c159d9b38 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/service/SpmService.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/service/SpmService.java @@ -18,29 +18,39 @@ */ package org.apache.fineract.spm.service; +import org.apache.fineract.infrastructure.core.exception.PlatformDataIntegrityException; import org.apache.fineract.infrastructure.security.service.PlatformSecurityContext; import org.apache.fineract.spm.domain.Survey; +import org.apache.fineract.spm.domain.SurveyValidator; +import org.apache.fineract.spm.exception.SurveyNotFoundException; import org.apache.fineract.spm.repository.SurveyRepository; +import org.apache.openjpa.persistence.EntityExistsException; import org.joda.time.DateTime; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.dao.DataIntegrityViolationException; +import org.springframework.orm.jpa.JpaSystemException; import org.springframework.stereotype.Service; -import org.springframework.transaction.annotation.Transactional; import java.util.Date; import java.util.List; +import javax.persistence.PersistenceException; + @Service public class SpmService { private final PlatformSecurityContext securityContext; private final SurveyRepository surveyRepository; + private final SurveyValidator surveyValidator; @Autowired public SpmService(final PlatformSecurityContext securityContext, - final SurveyRepository surveyRepository) { + final SurveyRepository surveyRepository, + final SurveyValidator surveyValidator) { super(); this.securityContext = securityContext; this.surveyRepository = surveyRepository; + this.surveyValidator = surveyValidator; } public List fetchValidSurveys() { @@ -51,61 +61,83 @@ public List fetchValidSurveys() { public Survey findById(final Long id) { this.securityContext.authenticatedUser(); - - return this.surveyRepository.findOne(id); + Survey survey = this.surveyRepository.findOne(id); + if (survey == null) { + throw new SurveyNotFoundException(id); + } + return survey; } public Survey createSurvey(final Survey survey) { this.securityContext.authenticatedUser(); - + this.surveyValidator.validate(survey); final Survey previousSurvey = this.surveyRepository.findByKey(survey.getKey(), new Date()); if (previousSurvey != null) { this.deactivateSurvey(previousSurvey.getId()); } - // set valid from to start of today - final DateTime validFrom = DateTime - .now() - .withHourOfDay(0) - .withMinuteOfHour(0) - .withSecondOfMinute(0) - .withMillisOfSecond(0); - + final DateTime validFrom = getStartOfToday(); survey.setValidFrom(validFrom.toDate()); - // set valid from to end in 100 years - final DateTime validTo = validFrom - .withDayOfMonth(31) - .withMonthOfYear(12) - .withHourOfDay(23) - .withMinuteOfHour(59) - .withSecondOfMinute(59) - .withMillisOfSecond(999) - .plusYears(100); + final DateTime validTo = validFrom.withDayOfMonth(31).withMonthOfYear(12).withHourOfDay(23).withMinuteOfHour(59) + .withSecondOfMinute(59).withMillisOfSecond(999).plusYears(100); survey.setValidTo(validTo.toDate()); - - return this.surveyRepository.save(survey); + try { + this.surveyRepository.saveAndFlush(survey); + } catch (final EntityExistsException dve) { + handleDataIntegrityIssues(dve, dve, survey.getKey()); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(dve.getMostSpecificCause(), dve, survey.getKey()); + } catch (final JpaSystemException dve) { + handleDataIntegrityIssues(dve.getMostSpecificCause(), dve, survey.getKey()); + } catch (final PersistenceException dve) { + handleDataIntegrityIssues(dve, dve, survey.getKey()); + } + return survey ; + } + + public Survey updateSurvey(final Survey survey) { + try { + this.surveyValidator.validate(survey); + this.surveyRepository.saveAndFlush(survey); + } catch (final EntityExistsException dve) { + handleDataIntegrityIssues(dve, dve, survey.getKey()); + } catch (final DataIntegrityViolationException dve) { + handleDataIntegrityIssues(dve.getMostSpecificCause(), dve, survey.getKey()); + } catch (final JpaSystemException dve) { + handleDataIntegrityIssues(dve.getMostSpecificCause(), dve, survey.getKey()); + } catch (final PersistenceException dve) { + handleDataIntegrityIssues(dve, dve, survey.getKey()); + } + return survey; } public void deactivateSurvey(final Long id) { this.securityContext.authenticatedUser(); - final Survey survey = this.surveyRepository.findOne(id); + final Survey survey = findById(id); + final DateTime dateTime = getStartOfToday().minusMillis(1); + survey.setValidTo(dateTime.toDate()); + + this.surveyRepository.save(survey); + } + + public static DateTime getStartOfToday() { + return DateTime.now().withHourOfDay(0).withMinuteOfHour(0).withSecondOfMinute(0).withMillisOfSecond(0); + } + + private void handleDataIntegrityIssues(final Throwable realCause, final Exception dve, String key) { - if (survey != null) { - // set valid to to yesterday night - final DateTime dateTime = DateTime - .now() - .withHourOfDay(23) - .withMinuteOfHour(59) - .withSecondOfMinute(59) - .withMillisOfSecond(999) - .minusDays(1); - survey.setValidTo(dateTime.toDate()); + if (realCause.getMessage().contains("m_survey_scorecards")) { throw new PlatformDataIntegrityException( + "error.msg.survey.cannot.be.modified.as.used.in.client.survey", + "Survey can not be edited as it is already used in client survey", "name", key); } - this.surveyRepository.save(survey); - } + if (realCause.getMessage().contains("key")) { throw new PlatformDataIntegrityException("error.msg.survey.duplicate.key", + "Survey with key already exists", "name", key); } + + throw new PlatformDataIntegrityException("error.msg.survey.unknown.data.integrity.issue", + "Unknown data integrity issue with resource: " + realCause.getMessage()); } } diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/util/ScorecardMapper.java b/fineract-provider/src/main/java/org/apache/fineract/spm/util/ScorecardMapper.java index c317ccd06b5..60588d8ea24 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/util/ScorecardMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/util/ScorecardMapper.java @@ -18,7 +18,10 @@ */ package org.apache.fineract.spm.util; -import org.apache.fineract.organisation.staff.domain.Staff; +import java.util.ArrayList; +import java.util.List; + +import org.apache.fineract.infrastructure.core.service.DateUtils; import org.apache.fineract.portfolio.client.domain.Client; import org.apache.fineract.spm.data.ScorecardData; import org.apache.fineract.spm.data.ScorecardValue; @@ -28,38 +31,12 @@ import org.apache.fineract.spm.domain.Survey; import org.apache.fineract.useradministration.domain.AppUser; -import java.util.*; - public class ScorecardMapper { private ScorecardMapper() { super(); } - public static List map(final List scorecards) { - final Map scorecardDataMap = new HashMap<>(); - ScorecardData scorecardData = null; - if (scorecards != null && scorecards.isEmpty()) { - for (Scorecard scorecard : scorecards) { - if ((scorecardData = scorecardDataMap.get(scorecard.getCreatedOn())) == null) { - scorecardData = new ScorecardData(); - scorecardDataMap.put(scorecard.getCreatedOn(), scorecardData); - scorecardData.setUserId(scorecard.getAppUser().getId()); - scorecardData.setClientId(scorecard.getClient().getId()); - scorecardData.setCreatedOn(scorecard.getCreatedOn()); - scorecardData.setScorecardValues(new ArrayList()); - } - - scorecardData.getScorecardValues().add(new ScorecardValue(scorecard.getQuestion().getId(), scorecard.getResponse().getId(), - scorecard.getValue())); - } - - return new ArrayList<>(scorecardDataMap.values()); - } - - return Collections.EMPTY_LIST; - } - public static List map(final ScorecardData scorecardData, final Survey survey, final AppUser appUser, final Client client) { final List scorecards = new ArrayList<>(); @@ -74,7 +51,7 @@ public static List map(final ScorecardData scorecardData, final Surve ScorecardMapper.setQuestionAndResponse(scorecardValue, scorecard, survey); scorecard.setAppUser(appUser); scorecard.setClient(client); - scorecard.setCreatedOn(scorecardData.getCreatedOn()); + scorecard.setCreatedOn(DateUtils.getLocalDateOfTenant().toDate()); scorecard.setValue(scorecardValue.getValue()); } } @@ -97,4 +74,4 @@ private static void setQuestionAndResponse(final ScorecardValue scorecardValue, } } } -} +} \ No newline at end of file diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyApiConstants.java b/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyApiConstants.java new file mode 100644 index 00000000000..6b935110529 --- /dev/null +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyApiConstants.java @@ -0,0 +1,44 @@ +/** + * 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.spm.util; + + +public class SurveyApiConstants { + + public static final String SURVEY_RESOURCE_NAME = "survey"; + public static final String keyParamName = "key"; + public static final String nameParamName = "name"; + public static final String countryCodeParamName = "countrycode"; + public static final String descriptionParamName = "description"; + public static final String sequenceNumberParamName = "sequenceNo"; + public static final String valueParamName = "value"; + public static final String questionParamName = "question"; + public static final String optionsParamName = "options"; + public static final String textParamName = "text"; + public static final String lengthParamName = "length"; + + //to validate length/max value + public static final Integer maxCountryCodeLength = 2; + public static final Integer maxTextLength = 255; + public static final Integer maxNameLength = 255; + public static final Integer maxKeyLength = 32; + public static final Integer maxOptionsValue = 9999; + public static final Integer maxDescriptionLength = 4000; + +} diff --git a/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyMapper.java b/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyMapper.java index 45ebd57d77e..db3718df2d0 100644 --- a/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyMapper.java +++ b/fineract-provider/src/main/java/org/apache/fineract/spm/util/SurveyMapper.java @@ -45,8 +45,7 @@ public static SurveyData map(final Survey survey) { return surveyData; } - public static Survey map(final SurveyData surveyData) { - final Survey survey = new Survey(); + public static Survey map(final SurveyData surveyData, Survey survey) { survey.setComponents(SurveyMapper.mapComponentDatas(surveyData.getComponentDatas(), survey)); survey.setQuestions(SurveyMapper.mapQuestionDatas(surveyData.getQuestionDatas(), survey)); survey.setKey(surveyData.getKey()); diff --git a/fineract-provider/src/main/resources/META-INF/spring/spmContext.xml b/fineract-provider/src/main/resources/META-INF/spring/spmContext.xml index 42481106b20..d057b105603 100644 --- a/fineract-provider/src/main/resources/META-INF/spring/spmContext.xml +++ b/fineract-provider/src/main/resources/META-INF/spring/spmContext.xml @@ -32,7 +32,7 @@ - +