From f2d456b11b9e9ecd3c84f1907f62f4a81fc690a2 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Tue, 17 Aug 2021 12:09:14 +0530 Subject: [PATCH 01/67] Ifix master data service (#19) * iFix-Master-Data-Service: Initial Commit * Update build-config.yml (#3) * Removed the local RequestHeader, ResponseHeader,Error,ErrorResponse,AuditDetails ,And added the same from common library Created the basic package structure and concrete classes. updated the tracer jar version to 2.0.0 snapshot * Chart of account service - Create v1 Post * Goverment Create API structuring * Governmet Create API * Chart of account service - modified the api end point and put the validation for user info * Update build-config.yml (#4) * Env variable added and updated the spring boot version to 2.3.3 * Updated tracer to ifix-tracer. * Updated groupId for ifix-services-common * add the @ToString,@EqualsAndHashCode model class level * Refactored goverment create API and search API * Recorrection of tracer dependency * Updated ifix-tracer version * COA search flow * Spring boot version change * Chart of Account - create api - tenant search * Update Dockerfile * Refactor responseInfo to responseHeader * Refactor majorHeadtype to majorHeadType * Chart of Account - create api - tenant search--> Review comment(s). (#8) * Rahu eat search api (#7) * MongoDB pass url instead of host and port * Removed unused property * Pk master data coa (#9) * Chart of Account - create api - tenant search--> Review comment(s). * Generic type serviceRequestRepository * Generic type serviceRequestRepository * Department search Api * MongoDb url config Co-authored-by: pintu-eGov * Project search API * Removed unused properties * Removed corresponding property from the code * Renamed property * Project search API (#10) * file name changes * Removed unused properties * MongoDB migration data and instructions. (#13) * MongoDB migration data and instructions. * Seed data and index mongo queries Co-authored-by: pintu-eGov * seed data for Coa and government * IFIX-242: EAT refactored to Expenditure (#16) * IFIX-242: EAT refactored to Expenditure * IFIX-242: location value has been removed * IFIX-242: tenant id in lower case * changing expenditure class name in seed data Co-authored-by: Rushang Dhanesha Co-authored-by: rushang7-eGov Co-authored-by: pintu-eGov Co-authored-by: rahu-dev Co-authored-by: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> --- build/build-config.yml | 5 + build/maven/Dockerfile | 3 +- .../ifix-master-data-service/.gitignore | 42 ++++ .../ifix-master-data-service/README.md | 20 ++ .../ifix-master-data-service/pom.xml | 102 ++++++++++ .../src/main/java/org/egov/Main.java | 16 ++ .../org/egov/config/MainConfiguration.java | 39 ++++ .../MasterDataServiceConfiguration.java | 38 ++++ .../main/java/org/egov/producer/Producer.java | 18 ++ .../repository/ChartOfAccountRepository.java | 40 ++++ .../egov/repository/DepartmentRepository.java | 31 +++ .../repository/ExpenditureRepository.java | 28 +++ .../egov/repository/GovernmentRepository.java | 33 +++ .../egov/repository/ProjectRepository.java | 24 +++ .../repository/ServiceRequestRepository.java | 48 +++++ .../ChartOfAccountQueryBuilder.java | 46 +++++ .../queryBuilder/DepartmentQueryBuilder.java | 30 +++ .../queryBuilder/ExpenditureQueryBuilder.java | 36 ++++ .../queryBuilder/ProjectQueryBuilder.java | 42 ++++ .../egov/service/COAEnrichmentService.java | 93 +++++++++ .../egov/service/ChartOfAccountService.java | 73 +++++++ .../service/DepartmentEnrichmentService.java | 22 ++ .../org/egov/service/DepartmentService.java | 50 +++++ .../org/egov/service/ExpenditureService.java | 30 +++ .../service/GovernmentEnrichmentService.java | 35 ++++ .../org/egov/service/GovernmentService.java | 59 ++++++ .../java/org/egov/service/ProjectService.java | 26 +++ .../src/main/java/org/egov/util/CoaUtil.java | 81 ++++++++ .../org/egov/util/MasterDataConstants.java | 28 +++ .../org/egov/util/MasterDataServiceUtil.java | 27 +++ .../org/egov/util/ResponseHeaderCreator.java | 25 +++ .../validator/ChartOfAccountValidator.java | 192 ++++++++++++++++++ .../egov/validator/DepartmentValidator.java | 66 ++++++ .../egov/validator/ExpenditureValidator.java | 51 +++++ .../egov/validator/GovernmentValidator.java | 73 +++++++ .../org/egov/validator/ProjectValidator.java | 70 +++++++ .../ChartOfAccountApiController.java | 69 +++++++ .../controllers/DepartmentApiController.java | 60 ++++++ .../controllers/ExpenditureApiController.java | 69 +++++++ .../web/controllers/FundApiController.java | 65 ++++++ .../controllers/GovernmentApiController.java | 83 ++++++++ .../web/controllers/ProjectApiController.java | 69 +++++++ .../java/org/egov/web/models/COARequest.java | 33 +++ .../java/org/egov/web/models/COAResponse.java | 45 ++++ .../egov/web/models/COASearchCriteria.java | 72 +++++++ .../org/egov/web/models/COASearchRequest.java | 32 +++ .../org/egov/web/models/ChartOfAccount.java | 77 +++++++ .../java/org/egov/web/models/Department.java | 45 ++++ .../egov/web/models/DepartmentRequest.java | 30 +++ .../egov/web/models/DepartmentResponse.java | 43 ++++ .../web/models/DepartmentSearchCriteria.java | 52 +++++ .../web/models/DepartmentSearchRequest.java | 30 +++ .../java/org/egov/web/models/Expenditure.java | 77 +++++++ .../egov/web/models/ExpenditureRequest.java | 30 +++ .../egov/web/models/ExpenditureResponse.java | 45 ++++ .../web/models/ExpenditureSearchCriteria.java | 50 +++++ .../web/models/ExpenditureSearchRequest.java | 32 +++ .../main/java/org/egov/web/models/Fund.java | 87 ++++++++ .../java/org/egov/web/models/FundRequest.java | 30 +++ .../org/egov/web/models/FundResponse.java | 43 ++++ .../egov/web/models/FundSearchCriteria.java | 78 +++++++ .../egov/web/models/FundSearchRequest.java | 30 +++ .../java/org/egov/web/models/Government.java | 41 ++++ .../egov/web/models/GovernmentRequest.java | 32 +++ .../egov/web/models/GovernmentResponse.java | 43 ++++ .../web/models/GovernmentSearchCriteria.java | 39 ++++ .../web/models/GovernmentSearchRequest.java | 30 +++ .../java/org/egov/web/models/Project.java | 61 ++++++ .../org/egov/web/models/ProjectRequest.java | 30 +++ .../org/egov/web/models/ProjectResponse.java | 43 ++++ .../web/models/ProjectSearchCriteria.java | 57 ++++++ .../egov/web/models/ProjectSearchRequest.java | 30 +++ .../java/org/egov/web/models/SubFund.java | 72 +++++++ .../src/main/resources/application.properties | 14 ++ .../migration/V20210811131300__create_index | 24 +++ .../V20210811131400__government_seed_data | 50 +++++ ...20210811131500__chart_of_account_seed_data | 71 +++++++ .../V20210811131600__department_seed_data | 48 +++++ .../V20210811131700__expenditure_seed_data | 33 +++ .../seed/V20210811131800__project_seed_data | 36 ++++ .../test/java/org/egov/TestConfiguration.java | 16 ++ .../ChartOfAccountApiControllerTest.java | 57 ++++++ .../DepartmentApiControllerTest.java | 57 ++++++ .../ExpenditureApiControllerTest.java | 57 ++++++ .../controllers/FundApiControllerTest.java | 57 ++++++ .../GovernmentApiControllerTest.java | 57 ++++++ .../controllers/ProjectApiControllerTest.java | 57 ++++++ 87 files changed, 4128 insertions(+), 2 deletions(-) create mode 100644 domain-services/ifix-master-data-service/.gitignore create mode 100644 domain-services/ifix-master-data-service/README.md create mode 100644 domain-services/ifix-master-data-service/pom.xml create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/Main.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/config/MainConfiguration.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/producer/Producer.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ChartOfAccountQueryBuilder.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/DepartmentQueryBuilder.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ExpenditureQueryBuilder.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/FundApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COARequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COAResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ChartOfAccount.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Department.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Fund.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectResponse.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchRequest.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/SubFund.java create mode 100644 domain-services/ifix-master-data-service/src/main/resources/application.properties create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131400__government_seed_data create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data create mode 100644 domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ChartOfAccountApiControllerTest.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/DepartmentApiControllerTest.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ExpenditureApiControllerTest.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/FundApiControllerTest.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/GovernmentApiControllerTest.java create mode 100644 domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ProjectApiControllerTest.java diff --git a/build/build-config.yml b/build/build-config.yml index 33103856..3f2afbda 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -12,3 +12,8 @@ config: build: - work-dir: "core/libraries/ifix-services-common" image-name: "ifix-services-common" + - name: "builds/iFix/domain-services/ifix-master-data-service" + build: + - work-dir: "domain-services/ifix-master-data-service" + image-name: "ifix-master-data-service" + dockerfile: "build/maven/Dockerfile" diff --git a/build/maven/Dockerfile b/build/maven/Dockerfile index 0a13f93d..c7aacd2a 100644 --- a/build/maven/Dockerfile +++ b/build/maven/Dockerfile @@ -1,5 +1,4 @@ - -FROM egovio/alpine-maven-builder-jdk-8:gcp AS build +FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build ARG WORK_DIR WORKDIR /app diff --git a/domain-services/ifix-master-data-service/.gitignore b/domain-services/ifix-master-data-service/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/domain-services/ifix-master-data-service/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/domain-services/ifix-master-data-service/README.md b/domain-services/ifix-master-data-service/README.md new file mode 100644 index 00000000..8f211900 --- /dev/null +++ b/domain-services/ifix-master-data-service/README.md @@ -0,0 +1,20 @@ +# iFIX-Master-Data-Service + +## MongoDB + +Please copy the commands written in the files mentioned below and execute them in Mongo Shell. Also, make sure you +are using the correct `database name`. You can switch to a particular database by executing the following command in +Mongo shell +``` +use +``` + +### Indexes +The list of necessary indexes are stored in the [migrations directory](./src/main/resources/db/migration). + +### Sample data +The commands to insert the sample data are stored in [seed directory](./src/main/resources/db/seed). Please follow +the order of the list of files while inserting this data. + +We can use the same sample data as an example to insert the actual data for whichever master data the create APIs +haven't been implemented yet. diff --git a/domain-services/ifix-master-data-service/pom.xml b/domain-services/ifix-master-data-service/pom.xml new file mode 100644 index 00000000..1c769189 --- /dev/null +++ b/domain-services/ifix-master-data-service/pom.xml @@ -0,0 +1,102 @@ + + 4.0.0 + org.egov + ifix-master-data-service + jar + ifix-master-data-service + 1.0.0 + + 1.8 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + + + org.egov.services + ifix-services-common + 0.0.1-SNAPSHOT + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/Main.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/Main.java new file mode 100644 index 00000000..568c9df3 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/Main.java @@ -0,0 +1,16 @@ +package org.egov; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = {"org.egov", "org.egov.web.controllers", "org.egov.config"}) +public class Main { + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MainConfiguration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MainConfiguration.java new file mode 100644 index 00000000..e4d1cb86 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MainConfiguration.java @@ -0,0 +1,39 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java new file mode 100644 index 00000000..3254833e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java @@ -0,0 +1,38 @@ +package org.egov.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +public class MasterDataServiceConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Value("${ifix.master.government.host}") + private String ifixMasterGovernmentHost; + + @Value("${ifix.master.government.context.path}") + private String ifixMasterGovernmentContextPath; + + @Value("${ifix.master.government.search.path}") + private String ifixMasterGovernmentSearchPath; + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/producer/Producer.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/producer/Producer.java new file mode 100644 index 00000000..e52243e7 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/producer/Producer.java @@ -0,0 +1,18 @@ +package org.egov.producer; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java new file mode 100644 index 00000000..4506e6a0 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java @@ -0,0 +1,40 @@ +package org.egov.repository; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.queryBuilder.ChartOfAccountQueryBuilder; +import org.egov.tracer.model.ServiceCallException; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; +import java.util.List; + +@Repository +@Slf4j +public class ChartOfAccountRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private ChartOfAccountQueryBuilder coaQueryBuilder; + + @Autowired + private RestTemplate restTemplate; + + public void save(ChartOfAccount chartOfAccount) { + mongoTemplate.save(chartOfAccount); + } + + public List search(COASearchCriteria searchCriteria) { + Query searchQuery = coaQueryBuilder.buildSearchQuery(searchCriteria); + return (mongoTemplate.find(searchQuery,ChartOfAccount.class)); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java new file mode 100644 index 00000000..c5c3b2f4 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java @@ -0,0 +1,31 @@ +package org.egov.repository; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.queryBuilder.DepartmentQueryBuilder; +import org.egov.web.models.ChartOfAccount; +import org.egov.web.models.Department; +import org.egov.web.models.DepartmentSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Slf4j +public class DepartmentRepository { + + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private DepartmentQueryBuilder departmentQueryBuilder; + + public List search(DepartmentSearchCriteria searchCriteria) { + Query searchQuery = departmentQueryBuilder.buildSearchQuery(searchCriteria); + return (mongoTemplate.find(searchQuery, Department.class)); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java new file mode 100644 index 00000000..5ea9a57e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java @@ -0,0 +1,28 @@ +package org.egov.repository; + +import org.egov.repository.queryBuilder.ExpenditureQueryBuilder; +import org.egov.web.models.Expenditure; +import org.egov.web.models.ExpenditureSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class ExpenditureRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + ExpenditureQueryBuilder expenditureQueryBuilder; + + /** + * @param expenditureSearchCriteria + * @return + */ + public List findAllByCriteria(ExpenditureSearchCriteria expenditureSearchCriteria) { + return mongoTemplate.find(expenditureQueryBuilder.buildQuerySearch(expenditureSearchCriteria), Expenditure.class); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java new file mode 100644 index 00000000..04aba47c --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java @@ -0,0 +1,33 @@ +package org.egov.repository; + +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class GovernmentRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + public void save(Government government) { + mongoTemplate.save(government); + } + + public Government findById(String governmentId) { + return mongoTemplate.findById(governmentId, Government.class); + } + + public List findAllByIdList(List idList) { + Query query = new Query(); + query.addCriteria(Criteria.where("id").in(idList)); + return mongoTemplate.find(query,Government.class); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java new file mode 100644 index 00000000..933c2ed2 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java @@ -0,0 +1,24 @@ +package org.egov.repository; + +import org.egov.repository.queryBuilder.ProjectQueryBuilder; +import org.egov.web.models.Project; +import org.egov.web.models.ProjectSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +public class ProjectRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + ProjectQueryBuilder projectQueryBuilder; + + public List findAllByCriteria(ProjectSearchCriteria projectSearchCriteria) { + return mongoTemplate.find(projectQueryBuilder.buildQuerySearch(projectSearchCriteria), Project.class); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java new file mode 100644 index 00000000..9ceea556 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java @@ -0,0 +1,48 @@ +package org.egov.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Repository; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Repository +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + /** + * @param uri + * @param request + * @return + */ + public Object fetchResult(String uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri, request, Map.class); + }catch(HttpClientErrorException e) { + log.error("External Service threw an Exception: ",e); + throw new ServiceCallException(e.getResponseBodyAsString()); + }catch(Exception e) { + log.error("Exception while fetching from searcher: ",e); + } + + return response; + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ChartOfAccountQueryBuilder.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ChartOfAccountQueryBuilder.java new file mode 100644 index 00000000..efb6ffc1 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ChartOfAccountQueryBuilder.java @@ -0,0 +1,46 @@ +package org.egov.repository.queryBuilder; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.web.models.COASearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ChartOfAccountQueryBuilder { + + + public Query buildSearchQuery(COASearchCriteria searchCriteria) { + + Criteria criteria = Criteria.where("tenantId").is(searchCriteria.getTenantId()); + + if (StringUtils.isNotBlank(searchCriteria.getMajorHead())) + criteria.and("majorHead").is(searchCriteria.getMajorHead()); + + if (StringUtils.isNotBlank(searchCriteria.getMinorHead())) + criteria.and("minorHead").is(searchCriteria.getMinorHead()); + + if (StringUtils.isNotBlank(searchCriteria.getGroupHead())) + criteria.and("groupHead").is(searchCriteria.getGroupHead()); + + if (StringUtils.isNotBlank(searchCriteria.getObjectHead())) + criteria.and("objectHead").is(searchCriteria.getObjectHead()); + + if (StringUtils.isNotBlank(searchCriteria.getSubHead())) + criteria.and("subHead").is(searchCriteria.getSubHead()); + + if (StringUtils.isNotBlank(searchCriteria.getSubMajorHead())) + criteria.and("subMajorHead").is(searchCriteria.getSubMajorHead()); + + if (StringUtils.isNotBlank(searchCriteria.getCoaCode())) + criteria.and("coaCode").is(searchCriteria.getCoaCode()); + + if (searchCriteria.getIds() != null && !searchCriteria.getIds().isEmpty()) + criteria.and("id").in(searchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/DepartmentQueryBuilder.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/DepartmentQueryBuilder.java new file mode 100644 index 00000000..c5570877 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/DepartmentQueryBuilder.java @@ -0,0 +1,30 @@ +package org.egov.repository.queryBuilder; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.web.models.DepartmentSearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class DepartmentQueryBuilder { + + public Query buildSearchQuery(DepartmentSearchCriteria searchCriteria) { + + Criteria criteria = Criteria.where("tenantId").is(searchCriteria.getTenantId()); + + if (StringUtils.isNotBlank(searchCriteria.getCode())) + criteria.and("code").is(searchCriteria.getCode()); + + if (StringUtils.isNotBlank(searchCriteria.getName())) + criteria.and("name").is(searchCriteria.getName()); + + if (searchCriteria.getIds() != null && !searchCriteria.getIds().isEmpty()) + criteria.and("id").in(searchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ExpenditureQueryBuilder.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ExpenditureQueryBuilder.java new file mode 100644 index 00000000..0b3c3366 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ExpenditureQueryBuilder.java @@ -0,0 +1,36 @@ +package org.egov.repository.queryBuilder; + +import org.apache.commons.lang3.StringUtils; +import org.egov.util.MasterDataConstants; +import org.egov.web.models.ExpenditureSearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +/** + * + */ +@Component +public class ExpenditureQueryBuilder { + + /** + * @param expenditureSearchCriteria + * @return + */ + public Query buildQuerySearch(ExpenditureSearchCriteria expenditureSearchCriteria) { + Criteria criteria = Criteria.where(MasterDataConstants.CRITERIA_TENANT_ID).is(expenditureSearchCriteria.getTenantId()); + + if (!StringUtils.isEmpty(expenditureSearchCriteria.getName())) { + criteria.and(MasterDataConstants.CRITERIA_NAME).is(expenditureSearchCriteria.getName()); + } + + if (!StringUtils.isEmpty(expenditureSearchCriteria.getCode())) { + criteria.and(MasterDataConstants.CRITERIA_CODE).is(expenditureSearchCriteria.getCode()); + } + + if (expenditureSearchCriteria.getIds() != null && !expenditureSearchCriteria.getIds().isEmpty()) + criteria.and(MasterDataConstants.CRITERIA_ID).in(expenditureSearchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java new file mode 100644 index 00000000..0a2645c3 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java @@ -0,0 +1,42 @@ +package org.egov.repository.queryBuilder; + +import org.apache.commons.lang3.StringUtils; +import org.egov.web.models.ProjectSearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +import java.util.Collections; + +@Component +public class ProjectQueryBuilder { + + public Query buildQuerySearch(ProjectSearchCriteria projectSearchCriteria) { + Criteria criteria = Criteria.where("tenantId").is(projectSearchCriteria.getTenantId()); + + if (!StringUtils.isEmpty(projectSearchCriteria.getName())) { + criteria.and("name").is(projectSearchCriteria.getName()); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getCode())) { + criteria.and("code").is(projectSearchCriteria.getCode()); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getLocationId())) { + criteria.and("locationIds").in(Collections.singletonList(projectSearchCriteria.getLocationId())); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getExpenditureId())) { + criteria.and("eatId").is(projectSearchCriteria.getExpenditureId()); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getDepartmentId())) { + criteria.and("departmentId").is(projectSearchCriteria.getDepartmentId()); + } + + if (projectSearchCriteria.getIds() != null && !projectSearchCriteria.getIds().isEmpty()) + criteria.and("id").in(projectSearchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java new file mode 100644 index 00000000..b5327d12 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java @@ -0,0 +1,93 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.ChartOfAccountRepository; +import org.egov.util.MasterDataServiceUtil; +import org.egov.validator.ChartOfAccountValidator; +import org.egov.web.models.COARequest; +import org.egov.web.models.COASearchCriteria; +import org.egov.web.models.COASearchRequest; +import org.egov.web.models.ChartOfAccount; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; +import java.util.UUID; + +@Service +@Slf4j +public class COAEnrichmentService { + + @Autowired + private MasterDataServiceUtil mdsUtil; + + @Autowired + private ChartOfAccountValidator chartOfAccountValidator; + /** + * Enrich the COA create request with COA code, id and audit details. + * + * @param coaRequest + */ + public void enrichCreatePost(COARequest coaRequest) { + ChartOfAccount chartOfAccount = coaRequest.getChartOfAccount(); + RequestHeader requestHeader = coaRequest.getRequestHeader(); + + createCoaCode(chartOfAccount); + COASearchCriteria coaSearchCriteria = createCOASearchCriteria(chartOfAccount); + chartOfAccountValidator.validateCoaCode(coaSearchCriteria); + + AuditDetails auditDetails = null; + /** + * check COA code is available in the Master system , if yes update the audit details and insert as a new record + * else insert as fresh record + */ + + if(chartOfAccount.getAuditDetails() == null){ + auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), chartOfAccount.getAuditDetails(), true); + }else{ + auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), chartOfAccount.getAuditDetails(), false); + } + + chartOfAccount.setAuditDetails(auditDetails); + chartOfAccount.setId(UUID.randomUUID().toString()); + + } + + private COASearchCriteria createCOASearchCriteria(ChartOfAccount chartOfAccount) { + COASearchCriteria searchCriteria = new COASearchCriteria(); + searchCriteria.setTenantId(chartOfAccount.getTenantId()); + searchCriteria.setCoaCode(chartOfAccount.getCoaCode()); + return searchCriteria; + } + + /** + * Create a COA code based on + * majorHead + * - subMajorHead + * - minorHead + * - subHead + * - groupHead + * - objectHead + * + * @param chartOfAccount + */ + protected void createCoaCode(ChartOfAccount chartOfAccount) { + StringBuilder coaCode = new StringBuilder(); + coaCode.append(chartOfAccount.getMajorHead()).append("-") + .append(chartOfAccount.getSubMajorHead()).append("-") + .append(chartOfAccount.getMinorHead()).append("-") + .append(chartOfAccount.getSubHead()).append("-") + .append(chartOfAccount.getGroupHead()).append("-") + .append(chartOfAccount.getObjectHead()); + + chartOfAccount.setCoaCode(coaCode.toString()); + } + + public void enrichSearchPost(COASearchRequest coaSearchRequest) { + COASearchCriteria searchCriteria = coaSearchRequest.getCriteria(); + //TODO- fill if any default search criteria + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java new file mode 100644 index 00000000..28de58b2 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java @@ -0,0 +1,73 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.producer.Producer; +import org.egov.repository.ChartOfAccountRepository; +import org.egov.validator.ChartOfAccountValidator; +import org.egov.web.models.COARequest; +import org.egov.web.models.COASearchCriteria; +import org.egov.web.models.COASearchRequest; +import org.egov.web.models.ChartOfAccount; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +@Slf4j +public class ChartOfAccountService { + + @Autowired + private ChartOfAccountValidator validator; + + @Autowired + private COAEnrichmentService enricher; + + @Autowired + private Producer producer; + + @Autowired + private MasterDataServiceConfiguration mdsConfig; + + @Autowired + private ChartOfAccountRepository coaRepository; + + /** + * upsert a COA in the Master data system. + * @param coaRequest + * @return + */ + public COARequest chartOfAccountV1CreatePost(COARequest coaRequest) { + validator.validateCreatePost(coaRequest); + enricher.enrichCreatePost(coaRequest); + //producer.push(mdsConfig.getCoaSaveTopic(),coaRequest); + coaRepository.save(coaRequest.getChartOfAccount()); + return coaRequest; + } + + + /** + * Search the Chart of Account based on search criteria + * @param coaSearchRequest + * @return + */ + public List chartOfAccountV1SearchPost(COASearchRequest coaSearchRequest) { + validator.validateSearchPost(coaSearchRequest); + enricher.enrichSearchPost(coaSearchRequest); + + COASearchCriteria searchCriteria = coaSearchRequest.getCriteria(); + + if (searchCriteria.isEmpty()) + Collections.emptyList(); + + List chartOfAccounts = coaRepository.search(searchCriteria); + + if (chartOfAccounts == null || chartOfAccounts.isEmpty()) + Collections.emptyList(); + + return chartOfAccounts; + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java new file mode 100644 index 00000000..1c88d8e4 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java @@ -0,0 +1,22 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.web.models.DepartmentSearchCriteria; +import org.egov.web.models.DepartmentSearchRequest; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class DepartmentEnrichmentService { + + /** + * Enrich the department search request + * @param searchRequest + */ + public void enrichSearchPost(DepartmentSearchRequest searchRequest) { + DepartmentSearchCriteria searchCriteria = searchRequest.getCriteria(); + //TODO- fill if any default search criteria + + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java new file mode 100644 index 00000000..f622a9c8 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java @@ -0,0 +1,50 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.DepartmentRepository; +import org.egov.validator.DepartmentValidator; +import org.egov.web.models.Department; +import org.egov.web.models.DepartmentSearchCriteria; +import org.egov.web.models.DepartmentSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +@Slf4j +public class DepartmentService { + + @Autowired + private DepartmentValidator validator; + + @Autowired + private DepartmentEnrichmentService enricher; + + @Autowired + private DepartmentRepository departmentRepo; + + /** + * Search the Department based on search criteria + * + * @param searchRequest + * @return + */ + public List departmentV1SearchPost(DepartmentSearchRequest searchRequest) { + validator.validateSearchPost(searchRequest); + enricher.enrichSearchPost(searchRequest); + + DepartmentSearchCriteria searchCriteria = searchRequest.getCriteria(); + if (searchCriteria.isEmpty()) + Collections.emptyList(); + + List departments = departmentRepo.search(searchCriteria); + + if (departments == null || departments.isEmpty()) + Collections.emptyList(); + + return departments; + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java new file mode 100644 index 00000000..1623756e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java @@ -0,0 +1,30 @@ +package org.egov.service; + +import org.egov.repository.ExpenditureRepository; +import org.egov.validator.ExpenditureValidator; +import org.egov.web.models.Expenditure; +import org.egov.web.models.ExpenditureSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ExpenditureService { + + @Autowired + ExpenditureRepository expenditureRepository; + + @Autowired + ExpenditureValidator expenditureValidator; + + /** + * @param expenditureSearchRequest + * @return + */ + public List findAllByCriteria(ExpenditureSearchRequest expenditureSearchRequest) { + expenditureValidator.validateExpenditureSearchRequest(expenditureSearchRequest); + return expenditureRepository.findAllByCriteria(expenditureSearchRequest.getCriteria()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java new file mode 100644 index 00000000..4e056a46 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java @@ -0,0 +1,35 @@ +package org.egov.service; + +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.MasterDataServiceUtil; +import org.egov.validator.GovernmentValidator; +import org.egov.web.models.ChartOfAccount; +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class GovernmentEnrichmentService { + + @Autowired + MasterDataServiceUtil enrichAuditDetails; + + public void enrichGovernmentData(GovernmentRequest governmentRequest) { + Government government = governmentRequest.getGovernment(); + RequestHeader requestHeader = governmentRequest.getRequestHeader(); + + AuditDetails auditDetails = null; + + if(government.getAuditDetails() == null){ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), government.getAuditDetails(), true); + }else{ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), government.getAuditDetails(), false); + } + + government.setAuditDetails(auditDetails); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java new file mode 100644 index 00000000..1c4438b4 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java @@ -0,0 +1,59 @@ +package org.egov.service; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.producer.Producer; +import org.egov.repository.GovernmentRepository; +import org.egov.tracer.model.ServiceCallException; +import org.egov.validator.GovernmentValidator; +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentRequest; +import org.egov.web.models.GovernmentSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.stereotype.Service; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.List; +import java.util.Map; + +@Service +public class GovernmentService { + + @Autowired + GovernmentValidator governmentValidator; + + @Autowired + GovernmentRepository governmentRepository; + + @Autowired + GovernmentEnrichmentService governmentEnrichmentService; + + @Autowired + private Producer producer; + + /** + * @param governmentRequest + * @return + */ + public GovernmentRequest addGovernment(GovernmentRequest governmentRequest) { + governmentValidator.validateGovernmentRequestData(governmentRequest); + governmentEnrichmentService.enrichGovernmentData(governmentRequest); + + governmentRepository.save(governmentRequest.getGovernment()); + + return governmentRequest; + } + + /** + * @param governmentSearchRequest + * @return + */ + public List searchAllGovernmentByIdList(GovernmentSearchRequest governmentSearchRequest) { + governmentValidator.validateGovernmentSearchRequestData(governmentSearchRequest); + + return governmentRepository.findAllByIdList(governmentSearchRequest.getCriteria().getIds()); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java new file mode 100644 index 00000000..c6a04b68 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java @@ -0,0 +1,26 @@ +package org.egov.service; + +import org.egov.repository.ProjectRepository; +import org.egov.validator.ProjectValidator; +import org.egov.web.models.Project; +import org.egov.web.models.ProjectSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.List; + +@Service +public class ProjectService { + + @Autowired + ProjectValidator projectValidator; + + @Autowired + ProjectRepository projectRepository; + + public List findAllByCriteria(ProjectSearchRequest projectSearchRequest) { + projectValidator.validateProjectSearchRequest(projectSearchRequest); + + return projectRepository.findAllByCriteria(projectSearchRequest.getCriteria()); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java new file mode 100644 index 00000000..cb07b814 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java @@ -0,0 +1,81 @@ +package org.egov.util; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.apache.kafka.common.protocol.types.Field; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ChartOfAccountRepository; +import org.egov.repository.ServiceRequestRepository; +import org.egov.web.models.*; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; + +@Component +@Slf4j +public class CoaUtil { + + @Autowired + private ServiceRequestRepository searchRequestRepository; + + @Autowired + private MasterDataServiceConfiguration mdsConfiguration; + + /** + * Search the Government service based on search criteria + * + * @param requestHeader + * @param chartOfAccount + */ + public List searchTenants(RequestHeader requestHeader, ChartOfAccount chartOfAccount) { + GovernmentSearchRequest govtSearchRequest = createSearchTenantRequest(requestHeader, chartOfAccount); + String url = createSearchTenantUrl(); + Object response = searchRequestRepository.fetchResult(url,govtSearchRequest); + if(response != null){ + LinkedHashMap linkedHashMap = (LinkedHashMap) response; + List governments = (List) linkedHashMap.get("government"); + return governments; + } + + return Collections.emptyList(); + } + + /** + * Create the government search Url + * + * @return + */ + private String createSearchTenantUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(mdsConfiguration.getIfixMasterGovernmentHost()) + .append(mdsConfiguration.getIfixMasterGovernmentContextPath()) + .append(mdsConfiguration.getIfixMasterGovernmentSearchPath()); + return uriBuilder.toString(); + } + + private GovernmentSearchRequest createSearchTenantRequest(RequestHeader requestHeader, ChartOfAccount chartOfAccount) { + GovernmentSearchRequest govtSearchRequest = new GovernmentSearchRequest(); + GovernmentSearchCriteria govtSearchCriteria = new GovernmentSearchCriteria(); + RequestHeader newRequestHeader = new RequestHeader(); + + BeanUtils.copyProperties(requestHeader, newRequestHeader); + + List ids = new ArrayList<>(); + if (StringUtils.isNotBlank(chartOfAccount.getTenantId())) { + ids.add(chartOfAccount.getTenantId()); + } + + govtSearchCriteria.setIds(ids); + govtSearchRequest.setCriteria(govtSearchCriteria); + govtSearchRequest.setRequestHeader(newRequestHeader); + + return govtSearchRequest; + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java new file mode 100644 index 00000000..61411fda --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -0,0 +1,28 @@ +package org.egov.util; + +public class MasterDataConstants { + public static final String CRITERIA_TENANT_ID = "tenantId"; + public static final String CRITERIA_NAME = "name"; + public static final String CRITERIA_CODE = "code"; + public static final String CRITERIA_ID = "id"; + + private MasterDataConstants() { + } + + + public static final String USER_INFO = "USER_INFO"; + public static final String GOVERNMENT_ID = "GOVERNMENT_ID"; + public static final String GOVERNMENT_NAME = "GOVERNMENT_NAME"; + public static final String TENANT_ID = "TENANT_ID"; + public static final String EXPENDITURE_NAME = "EXPENDITURE_NAME"; + public static final String EXPENDITURE_CODE = "EXPENDITURE_CODE"; + + public static final String REQUEST_PAYLOAD_MISSING = "REQUEST_PAYLOAD"; + public static final String PROJECT_NAME = "PROJECT_NAME"; + public static final String PROJECT_CODE = "PROJECT_CODE"; + public static final String EXPENDITURE_ID = "EXPENDITURE_ID"; + public static final String DEPARTMENT_ID = "DEPARTMENT_ID"; + public static final String LOCATION_ID = "LOCATION_ID"; + + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java new file mode 100644 index 00000000..f24ac427 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java @@ -0,0 +1,27 @@ +package org.egov.util; + + +import org.egov.common.contract.AuditDetails; +import org.egov.web.models.ChartOfAccount; +import org.springframework.stereotype.Component; + +@Component +public class MasterDataServiceUtil { + + /** + * Method to return auditDetails for create/update flows for COA + * + * @param by + * @param isCreate + * @return AuditDetails + */ + public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { + Long time = System.currentTimeMillis(); + if(isCreate) + return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); + else + return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) + .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java new file mode 100644 index 00000000..afe64b92 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -0,0 +1,25 @@ +package org.egov.util; + +import org.egov.common.contract.request.RequestHeader; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.stereotype.Component; + + +@Component +public class ResponseHeaderCreator { + + public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader requestInfo, final Boolean success) { + + final String correlationId = requestInfo != null ? requestInfo.getCorrelationId() : ""; + final String ver = requestInfo != null ? requestInfo.getVersion() : ""; + Long ts = null; + if (requestInfo != null) + ts = requestInfo.getTs(); + final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseHeader.builder().version(ver).ts(ts).msgId(msgId).correlationId(correlationId).signature(sign) + .status(responseStatus).build(); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java new file mode 100644 index 00000000..de4718af --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java @@ -0,0 +1,192 @@ +package org.egov.validator; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.ChartOfAccountRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.CoaUtil; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class ChartOfAccountValidator { + + + @Autowired + private CoaUtil coaUtil; + + @Autowired + private ChartOfAccountRepository coaRepository; + + public void validateCreatePost(COARequest coaRequest) { + log.info("Enter into ChartOfAccountValidator.validateCreatePost()"); + ChartOfAccount chartOfAccount = coaRequest.getChartOfAccount(); + RequestHeader requestHeader = coaRequest.getRequestHeader(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException("REQUEST_HEADER", "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put("USER_INFO", "User info is missing"); + } + + if (chartOfAccount == null) { + throw new CustomException("INVALID_REQUEST", "COA request is invalid"); + } + + //code validation + if (StringUtils.isBlank(chartOfAccount.getGroupHead())) { + throw new CustomException("GROUP_HEAD", "Group head Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getGroupHead()) && chartOfAccount.getGroupHead().length() != 2) { + errorMap.put("GROUP_HEAD_CODE_LENGTH", "Group head Code should be of length 2"); + } + if (StringUtils.isBlank(chartOfAccount.getMajorHead())) { + throw new CustomException("MAJOR_HEAD", "Major head Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getMajorHead()) && chartOfAccount.getMajorHead().length() != 4) { + errorMap.put("MAJOR_HEAD_CODE_LENGTH", "Major head Code should be of length 4"); + } + if (StringUtils.isBlank(chartOfAccount.getMinorHead())) { + throw new CustomException("MINOR_HEAD", "Minor head Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getMinorHead()) && chartOfAccount.getMinorHead().length() != 3) { + errorMap.put("MINOR_HEAD_CODE_LENGTH", "Minor head Code should be of length 3"); + } + if (StringUtils.isBlank(chartOfAccount.getSubHead())) { + throw new CustomException("SUB_HEAD", "Sub head Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getSubHead()) && chartOfAccount.getSubHead().length() != 2) { + errorMap.put("SUB_HEAD_CODE_LENGTH", "Sub head Code should be of length 2"); + } + if (StringUtils.isBlank(chartOfAccount.getObjectHead())) { + throw new CustomException("OBJECT_HEAD", "Object head Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getObjectHead()) && chartOfAccount.getObjectHead().length() != 2) { + errorMap.put("OBJECT_HEAD_CODE_LENGTH", "Object head Code should be of length 2"); + } + if (StringUtils.isBlank(chartOfAccount.getSubMajorHead())) { + throw new CustomException("SUB_MAJOR_HEAD", "Sub Major Code is mandatory for chart of account"); + } + if (StringUtils.isNotBlank(chartOfAccount.getSubMajorHead()) && chartOfAccount.getSubMajorHead().length() != 2) { + errorMap.put("SUB_MAJOR_HEAD_CODE_LENGTH", "Sub major head Code should be of length 2"); + } + + //Code name and type - validation + if (StringUtils.isNotBlank(chartOfAccount.getMajorHeadName()) + && (chartOfAccount.getMajorHeadName().length() < 2 || chartOfAccount.getMajorHeadName().length() > 64)) + errorMap.put("MAJOR_HEAD_NAME", "Major head name's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getMajorHeadType()) + && (chartOfAccount.getMajorHeadType().length() < 2 || chartOfAccount.getMajorHeadType().length() > 32)) + errorMap.put("MAJOR_HEAD_TYPE", "Major head type's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getSubMajorHeadName()) + && (chartOfAccount.getSubMajorHeadName().length() < 2 || chartOfAccount.getSubMajorHeadName().length() > 64)) + errorMap.put("SUB_MAJOR_HEAD_NAME", "Sub Major head name's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getMinorHeadName()) + && (chartOfAccount.getMinorHeadName().length() < 2 || chartOfAccount.getMinorHeadName().length() > 64)) + errorMap.put("MINOR_HEAD_NAME", "Minor head name's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getSubHeadName()) + && (chartOfAccount.getSubHeadName().length() < 2 || chartOfAccount.getSubHeadName().length() > 64)) + errorMap.put("SUB_HEAD_NAME", "Sub head name's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getGroupHeadName()) + && (chartOfAccount.getGroupHeadName().length() < 2 || chartOfAccount.getGroupHeadName().length() > 64)) + errorMap.put("GROUP_HEAD_NAME", "Group head name's length is invalid"); + + if (StringUtils.isNotBlank(chartOfAccount.getObjectHeadName()) + && (chartOfAccount.getObjectHeadName().length() < 2 || chartOfAccount.getObjectHeadName().length() > 64)) + errorMap.put("OBJECT_HEAD_NAME", "Object head name's length is invalid"); + + + //validate the tenant id is exist in the system or not + if (StringUtils.isNotBlank(chartOfAccount.getTenantId())) { + //call the Tenant Service for search, if doesn't exist add in the error map + List governments = coaUtil.searchTenants(requestHeader, chartOfAccount); + if (governments == null || governments.isEmpty()) { + errorMap.put("TENANT_ID", "Tenant id doesn't exist in the system"); + } + } + + + log.info("Exit from ChartOfAccountValidator.validateCreatePost()"); + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + + } + + public void validateCoaCode(COASearchCriteria searchCriteria) { + List chartOfAccounts = coaRepository.search(searchCriteria); + if (!chartOfAccounts.isEmpty()) + throw new CustomException("DUPLICATE_COA_CODE", "This coa code exists in the system"); + } + + public void validateSearchPost(COASearchRequest coaSearchRequest) { + log.info("Enter into ChartOfAccountValidator.validateSearchPost()"); + COASearchCriteria searchCriteria = coaSearchRequest.getCriteria(); + RequestHeader requestHeader = coaSearchRequest.getRequestHeader(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException("REQUEST_HEADER", "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put("USER_INFO", "User info is missing"); + } + + if (searchCriteria == null) { + throw new CustomException("INVALID_SEARCH_CRITERIA", "Search criteria is missing"); + } + //Tenant id validation + if (StringUtils.isBlank(searchCriteria.getTenantId())) { + errorMap.put("TENANT_ID", "Tenant id is mandatory"); + } + if (StringUtils.isNotBlank(searchCriteria.getTenantId()) + && (searchCriteria.getTenantId().length() < 2 || searchCriteria.getTenantId().length() > 64)) + errorMap.put("TENANT_ID_LENGTH", "Tenant id's length is invalid"); + + //Code validation + if (StringUtils.isNotBlank(searchCriteria.getGroupHead()) && searchCriteria.getGroupHead().length() != 2) { + errorMap.put("GROUP_HEAD_CODE_LENGTH", "Group head Code should be of length 2"); + } + if (StringUtils.isNotBlank(searchCriteria.getMajorHead()) && searchCriteria.getMajorHead().length() != 4) { + errorMap.put("MAJOR_HEAD_CODE_LENGTH", "Major head Code should be of length 4"); + } + if (StringUtils.isNotBlank(searchCriteria.getMinorHead()) && searchCriteria.getMinorHead().length() != 3) { + errorMap.put("MINOR_HEAD_CODE_LENGTH", "Minor head Code should be of length 3"); + } + if (StringUtils.isNotBlank(searchCriteria.getSubHead()) && searchCriteria.getSubHead().length() != 2) { + errorMap.put("SUB_HEAD_CODE_LENGTH", "Sub head Code should be of length 2"); + } + if (StringUtils.isNotBlank(searchCriteria.getObjectHead()) && searchCriteria.getObjectHead().length() != 2) { + errorMap.put("OBJECT_HEAD_CODE_LENGTH", "Object head Code should be of length 2"); + } + if (StringUtils.isNotBlank(searchCriteria.getSubMajorHead()) && searchCriteria.getSubMajorHead().length() != 2) { + errorMap.put("SUB_MAJOR_HEAD_CODE_LENGTH", "Sub major head Code should be of length 2"); + } + if (StringUtils.isNotBlank(searchCriteria.getCoaCode()) && (searchCriteria.getCoaCode().length() < 1 + || searchCriteria.getCoaCode().length()>64) ) { + errorMap.put("SUB_MAJOR_HEAD_CODE_LENGTH", "Sub major head Code should be of length 2"); + } + + + log.info("Exit from ChartOfAccountValidator.validateSearchPost()"); + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java new file mode 100644 index 00000000..cd813a10 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java @@ -0,0 +1,66 @@ +package org.egov.validator; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.DepartmentSearchCriteria; +import org.egov.web.models.DepartmentSearchRequest; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +@Component +@Slf4j +public class DepartmentValidator { + + + /** + * Validate the department search attribute(s) + * + * @param searchRequest + */ + public void validateSearchPost(DepartmentSearchRequest searchRequest) { + log.info("Enter into DepartmentValidator.validateSearchPost()"); + DepartmentSearchCriteria searchCriteria = searchRequest.getCriteria(); + RequestHeader requestHeader = searchRequest.getRequestHeader(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException("REQUEST_HEADER", "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put("USER_INFO", "User info is missing"); + } + + if (searchCriteria == null) { + throw new CustomException("INVALID_SEARCH_CRITERIA", "Search criteria is missing"); + } + + + //Tenant id validation + if (StringUtils.isBlank(searchCriteria.getTenantId())) { + throw new CustomException("TENANT_ID", "Tenant id is mandatory"); + } + if (StringUtils.isNotBlank(searchCriteria.getTenantId()) + && (searchCriteria.getTenantId().length() < 2 || searchCriteria.getTenantId().length() > 64)) + errorMap.put("TENANT_ID_LENGTH", "Tenant id's length is invalid"); + + //name + if (StringUtils.isNotBlank(searchCriteria.getName()) + && (searchCriteria.getName().length() < 2 || searchCriteria.getName().length() > 256)) + errorMap.put("DEPARTMENT_NAME", "Department name's length is invalid"); + + //code + if (StringUtils.isNotBlank(searchCriteria.getCode()) + && (searchCriteria.getCode().length() < 2 || searchCriteria.getCode().length() > 64)) + errorMap.put("DEPARTMENT_CODE", "Department code's length is invalid"); + + log.info("Exit from DepartmentValidator.validateSearchPost()"); + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java new file mode 100644 index 00000000..3b9aa63d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java @@ -0,0 +1,51 @@ +package org.egov.validator; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.util.MasterDataConstants; +import org.egov.web.models.ExpenditureSearchCriteria; +import org.egov.web.models.ExpenditureSearchRequest; +import org.springframework.stereotype.Component; + +@Component +public class ExpenditureValidator { + + public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditureSearchRequest) { + if (expenditureSearchRequest != null || expenditureSearchRequest.getRequestHeader() == null + && expenditureSearchRequest.getCriteria() != null) { + + RequestHeader requestHeader = expenditureSearchRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + throw new CustomException(MasterDataConstants.USER_INFO, "User information is missing"); + } + + ExpenditureSearchCriteria criteria = expenditureSearchRequest.getCriteria(); + + if (StringUtils.isEmpty(criteria.getTenantId())) { + throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); + } + + if (criteria.getTenantId().length() < 2 || criteria.getTenantId().length() > 64) { + throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + } + + if (!StringUtils.isEmpty(criteria.getName()) + && (criteria.getName().length() < 2 || criteria.getName().length() > 256)) { + throw new CustomException(MasterDataConstants.EXPENDITURE_NAME, "Expenditure name length is invalid. " + + "Length range [2-256]"); + } + + if (!StringUtils.isEmpty(criteria.getCode()) + && (criteria.getCode().length() < 2 || criteria.getCode().length() > 64)) { + throw new CustomException(MasterDataConstants.EXPENDITURE_CODE, "Expenditure code length is invalid. " + + "Length range [2-64]"); + } + + }else { + throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); + } + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java new file mode 100644 index 00000000..263df970 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java @@ -0,0 +1,73 @@ +package org.egov.validator; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.GovernmentRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.MasterDataConstants; +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentRequest; +import org.egov.web.models.GovernmentSearchCriteria; +import org.egov.web.models.GovernmentSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +public class GovernmentValidator { + + @Autowired + GovernmentRepository governmentRepository; + + public void validateGovernmentRequestData(GovernmentRequest governmentRequest) { + if (governmentRequest != null && governmentRequest.getGovernment() != null + && governmentRequest.getRequestHeader() != null) { + + RequestHeader requestHeader = governmentRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + throw new CustomException(MasterDataConstants.USER_INFO, "User information is missing"); + } + + Government government = governmentRequest.getGovernment(); + if (StringUtils.isEmpty(government.getId())) { + throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government Id (Tenant id) is missing in request data"); + } + + if (StringUtils.isEmpty(government.getName())) { + throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name is missing in request data"); + } + + Government existingGovernment = governmentRepository.findById(government.getId()); + if (existingGovernment != null) { + throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Duplicate government id"); + } + + if (government.getId().length() < 1 || government.getId().length() > 64) { + throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id length is invalid."); + } + + if (government.getName().length() < 2 || government.getName().length() > 256) { + throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name length is invalid"); + } + + }else { + throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); + } + } + + public void validateGovernmentSearchRequestData(GovernmentSearchRequest governmentSearchRequest) { + if (governmentSearchRequest != null && governmentSearchRequest.getRequestHeader() != null + && governmentSearchRequest.getCriteria() != null) { + + GovernmentSearchCriteria criteria = governmentSearchRequest.getCriteria(); + + if (criteria.getIds() == null || criteria.getIds().isEmpty()) { + throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id list are missing"); + } + + + } else { + throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); + } + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java new file mode 100644 index 00000000..7e8be781 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java @@ -0,0 +1,70 @@ +package org.egov.validator; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.util.MasterDataConstants; +import org.egov.web.models.ProjectSearchCriteria; +import org.egov.web.models.ProjectSearchRequest; +import org.springframework.stereotype.Component; + +@Component +public class ProjectValidator { + + public void validateProjectSearchRequest(ProjectSearchRequest projectSearchRequest) { + if (projectSearchRequest != null && projectSearchRequest.getRequestHeader() != null + && projectSearchRequest.getCriteria() != null) { + + RequestHeader requestHeader = projectSearchRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + throw new CustomException(MasterDataConstants.USER_INFO, "User information is missing"); + } + + ProjectSearchCriteria projectSearchCriteria = projectSearchRequest.getCriteria(); + + if (StringUtils.isEmpty(projectSearchCriteria.getTenantId())) { + throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); + } + + if (projectSearchCriteria.getTenantId().length() < 2 || projectSearchCriteria.getTenantId().length() > 64) { + throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getName()) + && (projectSearchCriteria.getName().length() < 2 || projectSearchCriteria.getName().length() > 256)) { + throw new CustomException(MasterDataConstants.PROJECT_NAME, "Project name length is invalid. " + + "Length range [2-256]"); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getCode()) + && (projectSearchCriteria.getCode().length() < 2 || projectSearchCriteria.getCode().length() > 64)) { + throw new CustomException(MasterDataConstants.PROJECT_CODE, "Project code length is invalid. " + + "Length range [2-64]"); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getExpenditureId()) + && (projectSearchCriteria.getExpenditureId().length() < 2 || projectSearchCriteria.getExpenditureId().length() > 64)) { + throw new CustomException(MasterDataConstants.EXPENDITURE_ID, "Expenditure id length is invalid. " + + "Length range [2-64]"); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getDepartmentId()) + && (projectSearchCriteria.getDepartmentId().length() < 2 + || projectSearchCriteria.getDepartmentId().length() > 64)) { + + throw new CustomException(MasterDataConstants.DEPARTMENT_ID, "Department id length is invalid. " + + "Length range [2-64]"); + } + + if (!StringUtils.isEmpty(projectSearchCriteria.getLocationId()) + && (projectSearchCriteria.getLocationId().length() < 2 + || projectSearchCriteria.getLocationId().length() > 64)) { + + throw new CustomException(MasterDataConstants.LOCATION_ID, "Location id length is invalid. " + + "Length range [2-64]"); + } + } + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java new file mode 100644 index 00000000..ed416b46 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java @@ -0,0 +1,69 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.ChartOfAccountService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.COARequest; +import org.egov.web.models.COAResponse; +import org.egov.web.models.COASearchRequest; +import org.egov.web.models.ChartOfAccount; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/chartOfAccount/v1") +public class ChartOfAccountApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private ChartOfAccountService chartOfAccountService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public ChartOfAccountApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity chartOfAccountV1CreatePost(@ApiParam(value = "Details for the new COA + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody COARequest body) { + + COARequest coaRequest = chartOfAccountService.chartOfAccountV1CreatePost(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + COAResponse coaResponse = COAResponse.builder().responseHeader(responseHeader) + .chartOfAccounts(Collections.singletonList(coaRequest.getChartOfAccount())).build(); + + return new ResponseEntity(coaResponse,HttpStatus.ACCEPTED); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity chartOfAccountV1SearchPost(@ApiParam(value = "RequestHeader meta data.", required = true) @Valid @RequestBody COASearchRequest body) { + List chartOfAccounts = chartOfAccountService.chartOfAccountV1SearchPost(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + COAResponse coaResponse = COAResponse.builder().responseHeader(responseHeader) + .chartOfAccounts(chartOfAccounts).build(); + + return new ResponseEntity(coaResponse,HttpStatus.OK); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java new file mode 100644 index 00000000..a217d682 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java @@ -0,0 +1,60 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.DepartmentService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/department/v1") +public class DepartmentApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private DepartmentService departmentService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public DepartmentApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity departmentV1CreatePost(@ApiParam(value = "Details for the new department + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody DepartmentRequest body) { + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity departmentV1SearchPost(@ApiParam(value = "Details for the department search criteria + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody DepartmentSearchRequest body) { + List departments = departmentService.departmentV1SearchPost(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + DepartmentResponse departmentResponse = DepartmentResponse.builder().responseHeader(responseHeader) + .department(departments).build(); + return new ResponseEntity(departmentResponse,HttpStatus.OK); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java new file mode 100644 index 00000000..97c430fe --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java @@ -0,0 +1,69 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.ExpenditureService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/expenditure/v1") +public class ExpenditureApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + ExpenditureService expenditureService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public ExpenditureApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity eatV1CreatePost(@ApiParam(value = "Details for the new expenditure RequestHeader" + + " (meta data of the API).", required = true) @Valid @RequestBody ExpenditureRequest body) { + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + /** + * @param body + * @return + */ + @RequestMapping(value = "_search", method = RequestMethod.POST) + public ResponseEntity eatV1SearchPost(@ApiParam(value = "Details for the expenditure search criteria " + + "RequestHeader (meta data of the API).", required = true) @Valid @RequestBody ExpenditureSearchRequest body) { + + List expenditureList = expenditureService.findAllByCriteria(body); + + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), + true); + + ExpenditureResponse eatResponse = ExpenditureResponse.builder().responseHeader(responseHeader).expenditure(expenditureList).build(); + + return new ResponseEntity<>(eatResponse, HttpStatus.ACCEPTED); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/FundApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/FundApiController.java new file mode 100644 index 00000000..7ca6099a --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/FundApiController.java @@ -0,0 +1,65 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.web.models.FundRequest; +import org.egov.web.models.FundResponse; +import org.egov.web.models.FundSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.io.IOException; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/eGovTrial/iFIX-Master-Data/1.0.0") +public class FundApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + public FundApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/fund/v1/_create", method = RequestMethod.POST) + public ResponseEntity fundV1CreatePost(@ApiParam(value = "Details for the new fund + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody FundRequest body) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("")) { + try { + return new ResponseEntity(objectMapper.readValue("", FundResponse.class), HttpStatus.NOT_IMPLEMENTED); + } catch (IOException e) { + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + @RequestMapping(value = "/fund/v1/_search", method = RequestMethod.POST) + public ResponseEntity fundV1SearchPost(@ApiParam(value = "RequestHeader meta data.", required = true) @Valid @RequestBody FundSearchRequest body) { + String accept = request.getHeader("Accept"); + if (accept != null && accept.contains("")) { + try { + return new ResponseEntity(objectMapper.readValue("", FundResponse.class), HttpStatus.NOT_IMPLEMENTED); + } catch (IOException e) { + return new ResponseEntity(HttpStatus.INTERNAL_SERVER_ERROR); + } + } + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java new file mode 100644 index 00000000..a055969c --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java @@ -0,0 +1,83 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.GovernmentService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/government/v1") +public class GovernmentApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private GovernmentService governmentService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public GovernmentApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + /** + * @param body + * @return + */ + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity governmentV1CreatePost(@ApiParam(value = + "Details for the governmet master data creation, RequestHeader (meta data of the API).", required = true) + @Valid @RequestBody GovernmentRequest body) { + + GovernmentRequest governmentRequest = governmentService.addGovernment(body); + + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + + GovernmentResponse governmentResponse = GovernmentResponse.builder().responseHeader(responseHeader) + .government(Collections.singletonList(governmentRequest.getGovernment())).build(); + + return new ResponseEntity(governmentResponse, HttpStatus.ACCEPTED); + } + + /** + * @param body + * @return + */ + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity governmentV1SearchPost(@ApiParam(value = "RequestHeader meta data.", + required = true) @Valid @RequestBody GovernmentSearchRequest body) { + + List governmentList = governmentService.searchAllGovernmentByIdList(body); + + ResponseHeader responseHeader = responseHeaderCreator + .createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + + GovernmentResponse governmentResponse = GovernmentResponse.builder().responseHeader(responseHeader) + .government(governmentList).build(); + + return new ResponseEntity(governmentResponse, HttpStatus.ACCEPTED); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java new file mode 100644 index 00000000..f2336153 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java @@ -0,0 +1,69 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.repository.ProjectRepository; +import org.egov.service.ProjectService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.io.IOException; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Controller +@RequestMapping("/project/v1") +public class ProjectApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private ProjectService projectService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public ProjectApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity projectV1CreatePost(@ApiParam(value = "Details for the new Project " + + "RequestHeader (meta data of the API).", required = true) @Valid @RequestBody ProjectRequest body) { + + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity projectV1SearchPost(@ApiParam(value = "Details for the Project search " + + "criteria RequestHeader (meta data of the API).", required = true) + @Valid @RequestBody ProjectSearchRequest body) { + + List projectList = projectService.findAllByCriteria(body); + + ResponseHeader responseHeader = responseHeaderCreator + .createResponseHeaderFromRequestHeader(body.getRequestHeader(),true); + + ProjectResponse projectResponse = ProjectResponse.builder().responseHeader(responseHeader) + .project(projectList).build(); + + return new ResponseEntity<>(projectResponse, HttpStatus.ACCEPTED); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COARequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COARequest.java new file mode 100644 index 00000000..a2e4ada8 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COARequest.java @@ -0,0 +1,33 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * COA request along with request metadata + */ +@ApiModel(description = "COA request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class COARequest { + + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("chartOfAccount") + private ChartOfAccount chartOfAccount = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COAResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COAResponse.java new file mode 100644 index 00000000..85121767 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COAResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched COA information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched COA information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class COAResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("chartOfAccounts") + @Valid + private List chartOfAccounts = null; + + + public COAResponse addChartOfAccountsItem(ChartOfAccount chartOfAccountsItem) { + if (this.chartOfAccounts == null) { + this.chartOfAccounts = new ArrayList<>(); + } + this.chartOfAccounts.add(chartOfAccountsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java new file mode 100644 index 00000000..20cb48b3 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java @@ -0,0 +1,72 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the fund + */ +@ApiModel(description = "The object contains all the search criteria of the fund") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class COASearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("majorHead") + private String majorHead = null; + + @JsonProperty("subMajorHead") + private String subMajorHead = null; + + @JsonProperty("minorHead") + private String minorHead = null; + + @JsonProperty("subHead") + private String subHead = null; + + @JsonProperty("groupHead") + private String groupHead = null; + + @JsonProperty("objectHead") + private String objectHead = null; + + @JsonProperty("coaCode") + private String coaCode = null; + + + public COASearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + + public boolean isEmpty(){ + return (StringUtils.isBlank(tenantId) && StringUtils.isBlank(majorHead) && StringUtils.isBlank(minorHead) + && StringUtils.isBlank(subHead) && StringUtils.isBlank(subMajorHead) && StringUtils.isBlank(groupHead) + && StringUtils.isBlank(objectHead) && (ids == null || ids.isEmpty()) && StringUtils.isBlank(coaCode)); + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchRequest.java new file mode 100644 index 00000000..958f12b1 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchRequest.java @@ -0,0 +1,32 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * COA search request along with request metadata. Defoult operator b/w multiple criteria is AND. + */ +@ApiModel(description = "COA search request along with request metadata. Defoult operator b/w multiple criteria is AND.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class COASearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private COASearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ChartOfAccount.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ChartOfAccount.java new file mode 100644 index 00000000..a75140d2 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ChartOfAccount.java @@ -0,0 +1,77 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Captures the COA data as map + */ +@ApiModel(description = "Captures the COA data as map") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class ChartOfAccount { + @JsonProperty("id") + private String id = null; + + @JsonProperty("coaCode") + private String coaCode = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("majorHead") + private String majorHead = null; + + @JsonProperty("majorHeadName") + private String majorHeadName = null; + + @JsonProperty("majorHeadType") + private String majorHeadType = null; + + @JsonProperty("subMajorHead") + private String subMajorHead = null; + + @JsonProperty("subMajorHeadName") + private String subMajorHeadName = null; + + @JsonProperty("minorHead") + private String minorHead = null; + + @JsonProperty("minorHeadName") + private String minorHeadName = null; + + @JsonProperty("subHead") + private String subHead = null; + + @JsonProperty("subHeadName") + private String subHeadName = null; + + @JsonProperty("groupHead") + private String groupHead = null; + + @JsonProperty("groupHeadName") + private String groupHeadName = null; + + @JsonProperty("objectHead") + private String objectHead = null; + + @JsonProperty("objectHeadName") + private String objectHeadName = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Department.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Department.java new file mode 100644 index 00000000..1e91ab0f --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Department.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Captures the department attributes + */ +@ApiModel(description = "Captures the department attributes") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Department { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("isNodal") + private Boolean isNodal = false; + + @JsonProperty("parent") + private String parent = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentRequest.java new file mode 100644 index 00000000..eb488d5e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department request along with request metadata + */ +@ApiModel(description = "Department request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("department") + private Department department = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentResponse.java new file mode 100644 index 00000000..58d6230f --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched Department information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched Department information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("department") + @Valid + private List department = null; + + + public DepartmentResponse addDepartmentItem(Department departmentItem) { + if (this.department == null) { + this.department = new ArrayList<>(); + } + this.department.add(departmentItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java new file mode 100644 index 00000000..b5cb8914 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java @@ -0,0 +1,52 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.apache.commons.lang3.StringUtils; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the Department + */ +@ApiModel(description = "The object contains all the search criteria of the Department") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentSearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("code") + private String code = null; + + + public DepartmentSearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + public boolean isEmpty(){ + return (StringUtils.isBlank(tenantId) && StringUtils.isBlank(name) && StringUtils.isBlank(code) + && (ids == null || ids.isEmpty())); + } +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchRequest.java new file mode 100644 index 00000000..21b445ed --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department search request along with request metadata. Defoult operator b/w multiple criteria is AND. + */ +@ApiModel(description = "Department search request along with request metadata. Defoult operator b/w multiple criteria is AND.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private DepartmentSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java new file mode 100644 index 00000000..a44d4574 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java @@ -0,0 +1,77 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * Captures the Expenditure attributes + */ +@ApiModel(description = "Captures the Expenditure attributes") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class Expenditure { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + @JsonProperty("type") + private TypeEnum type = null; + @JsonProperty("parent") + private String parent = null; + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + /** + * Capture the type of the Expenditure + */ + public enum TypeEnum { + SCHEME("Scheme"), + + NON_SCHEME("Non-Scheme"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureRequest.java new file mode 100644 index 00000000..ac62a5e4 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Expenditure request along with request metadata + */ +@ApiModel(description = "Expenditure request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ExpenditureRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("expenditure") + private Expenditure expenditure = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureResponse.java new file mode 100644 index 00000000..ee32b829 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureResponse.java @@ -0,0 +1,45 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched Expenditure information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched Expenditure information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class ExpenditureResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("expenditure") + @Valid + private List expenditure = null; + + + public ExpenditureResponse addEatItem(Expenditure expenditureItem) { + if (this.expenditure == null) { + this.expenditure = new ArrayList<>(); + } + this.expenditure.add(expenditureItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchCriteria.java new file mode 100644 index 00000000..15afbd82 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchCriteria.java @@ -0,0 +1,50 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the Expenditure + */ +@ApiModel(description = "The object contains all the search criteria of the Expenditure") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class ExpenditureSearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("code") + private String code = null; + + + public ExpenditureSearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchRequest.java new file mode 100644 index 00000000..ffc70410 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ExpenditureSearchRequest.java @@ -0,0 +1,32 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Expenditure search request along with request metadata. Defoult operator b/w multiple criteria is AND. + */ +@ApiModel(description = "Expenditure search request along with request metadata. Defoult operator b/w multiple criteria is AND.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class ExpenditureSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private ExpenditureSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Fund.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Fund.java new file mode 100644 index 00000000..b28d4918 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Fund.java @@ -0,0 +1,87 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * This object captures the information for fund and sub-fund + */ +@ApiModel(description = "This object captures the information for fund and sub-fund") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Fund { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + @JsonProperty("type") + private TypeEnum type = null; + @JsonProperty("subFund") + @Valid + private List subFund = new ArrayList<>(); + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + public Fund addSubFundItem(SubFund subFundItem) { + this.subFund.add(subFundItem); + return this; + } + + + /** + * type of fund + */ + public enum TypeEnum { + CSS("CSS"), + + FC("FC"), + + WB("WB"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundRequest.java new file mode 100644 index 00000000..c79fc8a6 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Fund request along with request metadata + */ +@ApiModel(description = "Fund request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FundRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("fund") + private Fund fund = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundResponse.java new file mode 100644 index 00000000..84b52c8f --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched fund information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched fund information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FundResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("funds") + @Valid + private List funds = null; + + + public FundResponse addFundsItem(Fund fundsItem) { + if (this.funds == null) { + this.funds = new ArrayList<>(); + } + this.funds.add(fundsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchCriteria.java new file mode 100644 index 00000000..94b7b083 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchCriteria.java @@ -0,0 +1,78 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the fund + */ +@ApiModel(description = "The object contains all the search criteria of the fund") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FundSearchCriteria { + @JsonProperty("fundIds") + @Valid + private List fundIds = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("fundCode") + @Valid + private List fundCode = null; + + @JsonProperty("subFundCode") + @Valid + private List subFundCode = null; + + @JsonProperty("subFundIds") + @Valid + private List subFundIds = null; + + + public FundSearchCriteria addFundIdsItem(String fundIdsItem) { + if (this.fundIds == null) { + this.fundIds = new ArrayList<>(); + } + this.fundIds.add(fundIdsItem); + return this; + } + + public FundSearchCriteria addFundCodeItem(String fundCodeItem) { + if (this.fundCode == null) { + this.fundCode = new ArrayList<>(); + } + this.fundCode.add(fundCodeItem); + return this; + } + + public FundSearchCriteria addSubFundCodeItem(String subFundCodeItem) { + if (this.subFundCode == null) { + this.subFundCode = new ArrayList<>(); + } + this.subFundCode.add(subFundCodeItem); + return this; + } + + public FundSearchCriteria addSubFundIdsItem(String subFundIdsItem) { + if (this.subFundIds == null) { + this.subFundIds = new ArrayList<>(); + } + this.subFundIds.add(subFundIdsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchRequest.java new file mode 100644 index 00000000..5152d028 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/FundSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Fund and sub fund search request along with request metadata + */ +@ApiModel(description = "Fund and sub fund search request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FundSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private FundSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java new file mode 100644 index 00000000..6dd97477 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java @@ -0,0 +1,41 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; + +/** + * This object captures the fiscal information of external systems. + */ +@ApiModel(description = "This object captures the fiscal information of external systems.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class Government { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("attributes") + private Object attributes = null; + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentRequest.java new file mode 100644 index 00000000..88569c8d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentRequest.java @@ -0,0 +1,32 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Tenant request along with request metadata + */ +@ApiModel(description = "Tenant request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class GovernmentRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("government") + private Government government = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentResponse.java new file mode 100644 index 00000000..c73074be --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched tenant information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched tenant information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GovernmentResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("government") + @Valid + private List government = null; + + + public GovernmentResponse addGovernmentItem(Government governmentItem) { + if (this.government == null) { + this.government = new ArrayList<>(); + } + this.government.add(governmentItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchCriteria.java new file mode 100644 index 00000000..4f76ecf2 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchCriteria.java @@ -0,0 +1,39 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the tenant + */ +@ApiModel(description = "The object contains all the search criteria of the tenant") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GovernmentSearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + + public GovernmentSearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchRequest.java new file mode 100644 index 00000000..967a8d1b --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/GovernmentSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Tenant search request along with request metadata + */ +@ApiModel(description = "Tenant search request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class GovernmentSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private GovernmentSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java new file mode 100644 index 00000000..76777054 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java @@ -0,0 +1,61 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Captures the Project attributes + */ +@ApiModel(description = "Captures the Project attributes") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Project { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("expenditureId") + private String expenditureId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("locationIds") + @Valid + private List locationIds = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + + public Project addLocationIdsItem(String locationIdsItem) { + if (this.locationIds == null) { + this.locationIds = new ArrayList<>(); + } + this.locationIds.add(locationIdsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectRequest.java new file mode 100644 index 00000000..2ea906fb --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Project request along with request metadata + */ +@ApiModel(description = "Project request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ProjectRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("project") + private Project project = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectResponse.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectResponse.java new file mode 100644 index 00000000..aa4ab82d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched Project information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched Project information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ProjectResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("project") + @Valid + private List project = null; + + + public ProjectResponse addProjectItem(Project projectItem) { + if (this.project == null) { + this.project = new ArrayList<>(); + } + this.project.add(projectItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java new file mode 100644 index 00000000..8addc77a --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java @@ -0,0 +1,57 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the Project + */ +@ApiModel(description = "The object contains all the search criteria of the Project") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ProjectSearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("expenditureId") + private String expenditureId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("locationId") + private String locationId = null; + + + public ProjectSearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchRequest.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchRequest.java new file mode 100644 index 00000000..9e2eb7af --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Project search request along with request metadata. Default operator b/w multiple criteria is AND + */ +@ApiModel(description = "Project search request along with request metadata. Default operator b/w multiple criteria is AND") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ProjectSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private ProjectSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/SubFund.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/SubFund.java new file mode 100644 index 00000000..486fcebc --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/SubFund.java @@ -0,0 +1,72 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +/** + * This object captures the fiscal information of external systems. + */ +@ApiModel(description = "This object captures the fiscal information of external systems.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class SubFund { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + @JsonProperty("type") + private TypeEnum type = null; + @JsonProperty("percentage") + private Double percentage = null; + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + /** + * type of sub fund + */ + public enum TypeEnum { + TIED("TIED"), + + UNTIED("UNTIED"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + + +} + diff --git a/domain-services/ifix-master-data-service/src/main/resources/application.properties b/domain-services/ifix-master-data-service/src/main/resources/application.properties new file mode 100644 index 00000000..fed6a7f3 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/application.properties @@ -0,0 +1,14 @@ +server.servlet.contextPath=/ifix-master-data +server.port=8030 +app.timezone=UTC + +org.egov.detailed.tracing.enabled = false + +#mongoDB +spring.data.mongodb.uri=mongodb://localhost:27017/?retryWrites=false +spring.data.mongodb.database=ifix_dev_db + +## Uri Configurations ## +ifix.master.government.host=http://localhost:8030 +ifix.master.government.context.path=/ifix-master-data +ifix.master.government.search.path=/government/v1/_search diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index new file mode 100644 index 00000000..289ec199 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index @@ -0,0 +1,24 @@ +db.government.createIndexes( + [{"name":1}] + ); +db.government.getIndexes(); + +db.department.createIndexes( + [{"name":1},{"code":1},{"tenantId":1}] + ); +db.department.getIndexes(); + +db.chartOfAccount.createIndexes( + [{"coaCode":1},{"majorHead":1},{"tenantId":1},{"subMajorHead":1},{"minorHead":1},{"subHead":1},{"groupHead":1},{"objectHead":1}] + ); +db.chartOfAccount.getIndexes(); + +db.eAT.createIndexes( + [{"name":1},{"code":1},{"tenantId":1}] +); +db.eAT.getIndexes(); + +db.project.createIndexes( + [{"name":1},{"code":1},{"tenantId":1},{"eatId":1},{"departmentId":1},{"locationIds":1}] +); +db.project.getIndexes(); \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131400__government_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131400__government_seed_data new file mode 100644 index 00000000..980f850e --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131400__government_seed_data @@ -0,0 +1,50 @@ +db.government.insertMany([ + { + "_id" : "pb", + "_class" : "org.egov.web.models.Government", + "name" : "Punjab", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155279383), + "lastModifiedTime" : NumberLong(1628155279383) + }, + "attributes" : {} +}, +{ + "_id" : "br", + "_class" : "org.egov.web.models.Government", + "name" : "Bihar", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "attributes" : {} +}, +{ + "_id" : "hr", + "name" : "Haryana", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628156764135), + "lastModifiedTime" : NumberLong(1628156764135) + }, + "attributes" : {}, + "_class" : "org.egov.web.models.Government" +}, +{ + "_id" : "up", + "name" : "Utter Pradesh", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628158324249), + "lastModifiedTime" : NumberLong(1628158324249) + }, + "attributes" : {}, + "_class" : "org.egov.web.models.Government" +} +]); \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data new file mode 100644 index 00000000..fedec5fc --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data @@ -0,0 +1,71 @@ +db.chartOfAccount.insertMany([ + { + "tenantId": "up", + "majorHead": "8243", + "majorHeadName": "majorHeadName82", + "majorHeadtype": "majorHeadtype", + "subMajorHead": "12", + "subMajorHeadName": "subMajorHeadName", + "minorHead": "373", + "minorHeadName": "minorHeadName347", + "subHead": "56", + "subHeadName": "subHeadName", + "groupHead": "78", + "groupHeadName": "groupHeadName", + "objectHead": "90", + "objectHeadName": "objectHeadName", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "_class": "org.egov.web.models.ChartOfAccount" + }, + { + "tenantId": "pb", + "majorHead": "8243", + "majorHeadName": "majorHeadName82", + "majorHeadtype": "majorHeadtype", + "subMajorHead": "12", + "subMajorHeadName": "subMajorHeadName", + "minorHead": "373", + "minorHeadName": "minorHeadName347", + "subHead": "56", + "subHeadName": "subHeadName", + "groupHead": "78", + "groupHeadName": "groupHeadName", + "objectHead": "90", + "objectHeadName": "objectHeadName", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "_class": "org.egov.web.models.ChartOfAccount" + }, + { + "tenantId": "PB", + "majorHead": "8943", + "majorHeadName": "majorHeadName89", + "majorHeadtype": "majorHeadtype", + "subMajorHead": "12", + "subMajorHeadName": "subMajorHeadName", + "minorHead": "567", + "minorHeadName": "minorHeadName347", + "subHead": "56", + "subHeadName": "subHeadName", + "groupHead": "78", + "groupHeadName": "groupHeadName", + "objectHead": "90", + "objectHeadName": "objectHeadName", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "_class": "org.egov.web.models.ChartOfAccount" + } +]); \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data new file mode 100644 index 00000000..31d4623d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data @@ -0,0 +1,48 @@ +db.department.insertMany([ +{ + "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ad2", + "tenantId": "pb", + "code": "dept01", + "name": "departmentName-1", + "isNodal": false, + "parent": "parent1", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "_class": "org.egov.web.models.Department" +}, +{ + "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ad3", + "tenantId": "PB", + "code": "dept02", + "name": "departmentName-2", + "isNodal": false, + "parent": "parent1", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + } +, + "_class": "org.egov.web.models.Department" +}, +{ + "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ad4", + "tenantId": "PB", + "code": "dept03", + "name": "departmentName-3", + "isNodal": false, + "parent": "parent1", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + }, + "_class": "org.egov.web.models.Department" +} +]); diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data new file mode 100644 index 00000000..e94f958d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data @@ -0,0 +1,33 @@ +db.expenditure.insertMany([ +{ + "_id" : "910f4d23-fc63-48fb-a8fb-f0ad567b788a", + "_class" : "org.egov.web.models.Expenditure", + "tenantId" : "pb", + "code" : "12345", + "name" : "Exp-1", + "type" : "SCHEME", + "departmentId" : "3d9ef18a-361a-40cf-b142-dd6f998e1ad2", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + } + +}, +{ + "_id" : "a4c21fc1-28df-494b-8983-baf3c6b027d7", + "_class" : "org.egov.web.models.Expenditure", + "tenantId" : "br", + "code" : "123", + "name" : "Exp-2", + "type" : "NON_SCHEME", + "departmentId" : "3d9ef18a-361a-40cf-b142-dd6f998e1ad3", + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628155293725), + "lastModifiedTime" : NumberLong(1628155293725) + } +} +]); diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data new file mode 100644 index 00000000..8c91396a --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data @@ -0,0 +1,36 @@ +db.project.insertMany([ +{ + "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ac4", + "tenantId": "hr", + "code": "PR2", + "name": "Project2", + "expenditureId": "910f4d23-fc63-48fb-a8fb-f0ad567b788a", + "departmentId": "3d9ef18a-361a-40cf-b142-dd6f998e1ad2", + "locationIds": [ + ], + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628063909104), + "lastModifiedTime" : NumberLong(1628063909104) + }, + "_class": "org.egov.web.models.Project" +}, +{ + "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ac5", + "tenantId": "pb", + "code": "PR3", + "name": "Project3", + "expenditureId": "a4c21fc1-28df-494b-8983-baf3c6b027d7", + "departmentId": "3d9ef18a-361a-40cf-b142-dd6f998e1ad3", + "locationIds": [ + ], + "auditDetails" : { + "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "lastModifiedBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", + "createdTime" : NumberLong(1628063909104), + "lastModifiedTime" : NumberLong(1628063909104) + }, + "_class": "org.egov.web.models.Project" +} +]); \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ChartOfAccountApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ChartOfAccountApiControllerTest.java new file mode 100644 index 00000000..85be58cc --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ChartOfAccountApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for ChartOfAccountApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(ChartOfAccountApiController.class) +@Import(TestConfiguration.class) +public class ChartOfAccountApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void chartOfAccountV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/chartOfAccount/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void chartOfAccountV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/chartOfAccount/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void chartOfAccountV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/chartOfAccount/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void chartOfAccountV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/chartOfAccount/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/DepartmentApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/DepartmentApiControllerTest.java new file mode 100644 index 00000000..5456272f --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/DepartmentApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for DepartmentApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(DepartmentApiController.class) +@Import(TestConfiguration.class) +public class DepartmentApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void departmentV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/department/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/department/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void departmentV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/department/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/department/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ExpenditureApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ExpenditureApiControllerTest.java new file mode 100644 index 00000000..76a3180b --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ExpenditureApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for ExpenditureIdApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(ExpenditureApiController.class) +@Import(TestConfiguration.class) +public class ExpenditureApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void eatV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/expenditure/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void eatV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/expenditure/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void eatV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/expenditure/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void eatV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/expenditure/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/FundApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/FundApiControllerTest.java new file mode 100644 index 00000000..ffe0d290 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/FundApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for FundApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(FundApiController.class) +@Import(TestConfiguration.class) +public class FundApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void fundV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/fund/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void fundV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/fund/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void fundV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/fund/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void fundV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/fund/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/GovernmentApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/GovernmentApiControllerTest.java new file mode 100644 index 00000000..8d534b62 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/GovernmentApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for GovernmentApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(GovernmentApiController.class) +@Import(TestConfiguration.class) +public class GovernmentApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void governmentV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/government/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void governmentV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/government/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void governmentV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/government/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void governmentV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/government/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} diff --git a/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ProjectApiControllerTest.java b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ProjectApiControllerTest.java new file mode 100644 index 00000000..33defb81 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/test/java/org/egov/web/controllers/ProjectApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for ProjectApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(ProjectApiController.class) +@Import(TestConfiguration.class) +public class ProjectApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void projectV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/project/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void projectV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/project/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void projectV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/project/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void projectV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Master-Data/1.0.0/project/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} From e08e80a87f106c4ee01077c0e442bc1307b64ac6 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 18 Aug 2021 12:06:25 +0530 Subject: [PATCH 02/67] Ifix master patch (#20) * iFix-Master-Data-Service: Initial Commit * Update build-config.yml (#3) * Removed the local RequestHeader, ResponseHeader,Error,ErrorResponse,AuditDetails ,And added the same from common library Created the basic package structure and concrete classes. updated the tracer jar version to 2.0.0 snapshot * Chart of account service - Create v1 Post * Goverment Create API structuring * Governmet Create API * Chart of account service - modified the api end point and put the validation for user info * Update build-config.yml (#4) * Env variable added and updated the spring boot version to 2.3.3 * Updated tracer to ifix-tracer. * Updated groupId for ifix-services-common * add the @ToString,@EqualsAndHashCode model class level * Refactored goverment create API and search API * Recorrection of tracer dependency * Updated ifix-tracer version * COA search flow * Spring boot version change * Chart of Account - create api - tenant search * Update Dockerfile * Refactor responseInfo to responseHeader * Refactor majorHeadtype to majorHeadType * Chart of Account - create api - tenant search--> Review comment(s). (#8) * Rahu eat search api (#7) * MongoDB pass url instead of host and port * Removed unused property * Pk master data coa (#9) * Chart of Account - create api - tenant search--> Review comment(s). * Generic type serviceRequestRepository * Generic type serviceRequestRepository * Department search Api * MongoDb url config Co-authored-by: pintu-eGov * Project search API * Removed unused properties * Removed corresponding property from the code * Renamed property * Project search API (#10) * file name changes * Removed unused properties * MongoDB migration data and instructions. (#13) * MongoDB migration data and instructions. * Seed data and index mongo queries Co-authored-by: pintu-eGov * seed data for Coa and government * IFIX-242: EAT refactored to Expenditure (#16) * IFIX-242: EAT refactored to Expenditure * IFIX-242: location value has been removed * IFIX-242: tenant id in lower case * changing expenditure class name in seed data * Id addition in COA * updated the read me * updated the read me Co-authored-by: Rushang Dhanesha Co-authored-by: rushang7-eGov Co-authored-by: pintu-eGov Co-authored-by: rahu-dev Co-authored-by: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> --- domain-services/ifix-master-data-service/README.md | 11 +++++++++++ .../seed/V20210811131500__chart_of_account_seed_data | 3 +++ 2 files changed, 14 insertions(+) diff --git a/domain-services/ifix-master-data-service/README.md b/domain-services/ifix-master-data-service/README.md index 8f211900..91f3e06d 100644 --- a/domain-services/ifix-master-data-service/README.md +++ b/domain-services/ifix-master-data-service/README.md @@ -1,5 +1,16 @@ # iFIX-Master-Data-Service +## Connect to MongoDB through Playground pod +Check the correct running mongodb pod and execute the below command +``` +kubectl exec -it -- /bin/bash +``` + +For connecting to particular running mongodb, run the below command +``` +mongo --host -u -p +``` + ## MongoDB Please copy the commands written in the files mentioned below and execute them in Mongo Shell. Also, make sure you diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data index fedec5fc..838c202c 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data @@ -1,5 +1,6 @@ db.chartOfAccount.insertMany([ { + "_id": "50cc5634-6cc3-456b-ae33-e40741128cdc", "tenantId": "up", "majorHead": "8243", "majorHeadName": "majorHeadName82", @@ -23,6 +24,7 @@ db.chartOfAccount.insertMany([ "_class": "org.egov.web.models.ChartOfAccount" }, { + "_id": "50cc5634-6cc3-456b-ae33-e40741128cde", "tenantId": "pb", "majorHead": "8243", "majorHeadName": "majorHeadName82", @@ -46,6 +48,7 @@ db.chartOfAccount.insertMany([ "_class": "org.egov.web.models.ChartOfAccount" }, { + "_id": "50cc5634-6cc3-456b-ae33-e40741128cd3", "tenantId": "PB", "majorHead": "8943", "majorHeadName": "majorHeadName89", From 1fa6c54f17a9f92295a697959a3d87162a11111e Mon Sep 17 00:00:00 2001 From: nikesh-eGov <48427967+nikesh-eGov@users.noreply.github.com> Date: Wed, 18 Aug 2021 12:06:58 +0530 Subject: [PATCH 03/67] Update CODEOWNERS --- CODEOWNERS | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CODEOWNERS b/CODEOWNERS index 623df7c7..09d8a63f 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -1,4 +1,4 @@ * @sathishp-eGov -core/* @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov -reference-adapter/* @manikanta-pt-eGov @sathishp-eGov @GhanshyamRawat-eGov -domain-services/* @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov +core/ @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov +reference-adapter/ @manikanta-pt-eGov @sathishp-eGov @GhanshyamRawat-eGov +domain-services/ @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov From a94ca17d3aa7a18046be6898a6546d3e05b4d738 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 18 Aug 2021 23:18:17 -0700 Subject: [PATCH 04/67] Ifix seed data (#21) * iFix-Master-Data-Service: Initial Commit * Update build-config.yml (#3) * Removed the local RequestHeader, ResponseHeader,Error,ErrorResponse,AuditDetails ,And added the same from common library Created the basic package structure and concrete classes. updated the tracer jar version to 2.0.0 snapshot * Chart of account service - Create v1 Post * Goverment Create API structuring * Governmet Create API * Chart of account service - modified the api end point and put the validation for user info * Update build-config.yml (#4) * Env variable added and updated the spring boot version to 2.3.3 * Updated tracer to ifix-tracer. * Updated groupId for ifix-services-common * add the @ToString,@EqualsAndHashCode model class level * Refactored goverment create API and search API * Recorrection of tracer dependency * Updated ifix-tracer version * COA search flow * Spring boot version change * Chart of Account - create api - tenant search * Update Dockerfile * Refactor responseInfo to responseHeader * Refactor majorHeadtype to majorHeadType * Chart of Account - create api - tenant search--> Review comment(s). (#8) * Rahu eat search api (#7) * MongoDB pass url instead of host and port * Removed unused property * Pk master data coa (#9) * Chart of Account - create api - tenant search--> Review comment(s). * Generic type serviceRequestRepository * Generic type serviceRequestRepository * Department search Api * MongoDb url config Co-authored-by: pintu-eGov * Project search API * Removed unused properties * Removed corresponding property from the code * Renamed property * Project search API (#10) * file name changes * Removed unused properties * MongoDB migration data and instructions. (#13) * MongoDB migration data and instructions. * Seed data and index mongo queries Co-authored-by: pintu-eGov * seed data for Coa and government * IFIX-242: EAT refactored to Expenditure (#16) * IFIX-242: EAT refactored to Expenditure * IFIX-242: location value has been removed * IFIX-242: tenant id in lower case * changing expenditure class name in seed data * Id addition in COA * Tenant Id changes Co-authored-by: Rushang Dhanesha Co-authored-by: rushang7-eGov Co-authored-by: pintu-eGov Co-authored-by: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> --- .../db/seed/V20210811131500__chart_of_account_seed_data | 4 ++-- .../resources/db/seed/V20210811131600__department_seed_data | 4 ++-- .../resources/db/seed/V20210811131700__expenditure_seed_data | 2 +- .../main/resources/db/seed/V20210811131800__project_seed_data | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data index 838c202c..fa61066a 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data @@ -1,7 +1,7 @@ db.chartOfAccount.insertMany([ { "_id": "50cc5634-6cc3-456b-ae33-e40741128cdc", - "tenantId": "up", + "tenantId": "pb", "majorHead": "8243", "majorHeadName": "majorHeadName82", "majorHeadtype": "majorHeadtype", @@ -49,7 +49,7 @@ db.chartOfAccount.insertMany([ }, { "_id": "50cc5634-6cc3-456b-ae33-e40741128cd3", - "tenantId": "PB", + "tenantId": "pb", "majorHead": "8943", "majorHeadName": "majorHeadName89", "majorHeadtype": "majorHeadtype", diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data index 31d4623d..65926ba6 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131600__department_seed_data @@ -16,7 +16,7 @@ db.department.insertMany([ }, { "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ad3", - "tenantId": "PB", + "tenantId": "pb", "code": "dept02", "name": "departmentName-2", "isNodal": false, @@ -32,7 +32,7 @@ db.department.insertMany([ }, { "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ad4", - "tenantId": "PB", + "tenantId": "pb", "code": "dept03", "name": "departmentName-3", "isNodal": false, diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data index e94f958d..d10b0dbb 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131700__expenditure_seed_data @@ -18,7 +18,7 @@ db.expenditure.insertMany([ { "_id" : "a4c21fc1-28df-494b-8983-baf3c6b027d7", "_class" : "org.egov.web.models.Expenditure", - "tenantId" : "br", + "tenantId" : "pb", "code" : "123", "name" : "Exp-2", "type" : "NON_SCHEME", diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data index 8c91396a..db6f3e9a 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131800__project_seed_data @@ -1,7 +1,7 @@ db.project.insertMany([ { "_id": "3d9ef18a-361a-40cf-b142-dd6f998e1ac4", - "tenantId": "hr", + "tenantId": "pb", "code": "PR2", "name": "Project2", "expenditureId": "910f4d23-fc63-48fb-a8fb-f0ad567b788a", From 7ebd307daf805678955210058c23e82c34eb20ad Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Mon, 23 Aug 2021 07:53:48 +0530 Subject: [PATCH 05/67] ifix services common (#23) * Created ifix-services-common library * Update domain name * Update build-config.yml (#3) * Update build-config.yml (#4) * ifix-tracer library * Update build-config.yml (#5) * Added dockerfile and Changed settings * Update dependency repositories * Updated groupId * Updated ifix-tracer for Spring 2 --- build/build-config.yml | 4 + .../libraries/ifix-services-common/.gitignore | 42 +++ .../libraries/ifix-services-common/Dockerfile | 17 ++ core/libraries/ifix-services-common/pom.xml | 73 ++++++ .../ifix-services-common/settings.xml | 23 ++ .../egov/common/contract/AuditDetails.java | 19 ++ .../contract/request/RequestHeader.java | 21 ++ .../common/contract/request/UserInfo.java | 21 ++ .../egov/common/contract/response/Error.java | 18 ++ .../contract/response/ErrorResponse.java | 19 ++ .../contract/response/ResponseHeader.java | 21 ++ core/libraries/ifix-tracer/.gitignore | 24 ++ core/libraries/ifix-tracer/Dockerfile | 17 ++ core/libraries/ifix-tracer/README.md | 122 +++++++++ core/libraries/ifix-tracer/pom.xml | 145 ++++++++++ core/libraries/ifix-tracer/settings.xml | 23 ++ .../java/org/egov/tracer/ExceptionAdvise.java | 248 ++++++++++++++++++ .../tracer/KafkaConsumerErrorHandler.java | 37 +++ .../tracer/config/ObjectMapperFactory.java | 25 ++ .../config/OpenTracingConfiguration.java | 81 ++++++ .../tracer/config/TracerConfiguration.java | 78 ++++++ .../egov/tracer/config/TracerProperties.java | 31 +++ .../tracer/constants/TracerConstants.java | 15 ++ .../java/org/egov/tracer/http/HttpUtils.java | 18 ++ .../http/RestTemplateLoggingInterceptor.java | 114 ++++++++ .../http/filters/MultiReadRequestWrapper.java | 81 ++++++ .../tracer/http/filters/TracerFilter.java | 192 ++++++++++++++ .../tracer/kafka/CustomKafkaTemplate.java | 55 ++++ .../egov/tracer/kafka/ErrorQueueProducer.java | 42 +++ .../KafkaTemplateLoggingInterceptors.java | 132 ++++++++++ .../tracer/kafka/LogAwareKafkaTemplate.java | 97 +++++++ .../deserializer/HashMapDeserializer.java | 14 + .../ISTTimeZoneHashMapDeserializer.java | 23 ++ .../serializer/ISTTimeZoneJsonSerializer.java | 22 ++ .../model/CustomBindingResultExceprion.java | 18 ++ .../egov/tracer/model/CustomException.java | 35 +++ .../java/org/egov/tracer/model/Error.java | 31 +++ .../egov/tracer/model/ErrorQueueContract.java | 26 ++ .../java/org/egov/tracer/model/ErrorRes.java | 27 ++ .../tracer/model/ServiceCallException.java | 16 ++ .../resources/logback-spring-json.xml.bak | 43 +++ .../src/main/resources/logback-spring.xml | 53 ++++ .../src/main/resources/tracer.properties | 24 ++ .../test/java/org/egov/ObjectMapperTest.java | 58 ++++ .../src/test/java/org/egov/Resources.java | 17 ++ .../kafka/KafkaListenerLoggingAspectTest.java | 246 +++++++++++++++++ ...WithCorrelationIdPresentInRequestInfo.json | 6 + ...houtCorrelationIdPresentInRequestInfo.json | 6 + .../requestBodyWithoutRequestInfoField.json | 3 + core/libraries/ifix-tracer/verify.sh | 2 + 50 files changed, 2525 insertions(+) create mode 100644 core/libraries/ifix-services-common/.gitignore create mode 100644 core/libraries/ifix-services-common/Dockerfile create mode 100644 core/libraries/ifix-services-common/pom.xml create mode 100644 core/libraries/ifix-services-common/settings.xml create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/AuditDetails.java create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/RequestHeader.java create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/UserInfo.java create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/Error.java create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ErrorResponse.java create mode 100644 core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ResponseHeader.java create mode 100644 core/libraries/ifix-tracer/.gitignore create mode 100644 core/libraries/ifix-tracer/Dockerfile create mode 100644 core/libraries/ifix-tracer/README.md create mode 100644 core/libraries/ifix-tracer/pom.xml create mode 100644 core/libraries/ifix-tracer/settings.xml create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/ExceptionAdvise.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/KafkaConsumerErrorHandler.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/ObjectMapperFactory.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/OpenTracingConfiguration.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerConfiguration.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerProperties.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/constants/TracerConstants.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/HttpUtils.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/RestTemplateLoggingInterceptor.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/MultiReadRequestWrapper.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/TracerFilter.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/CustomKafkaTemplate.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/ErrorQueueProducer.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/KafkaTemplateLoggingInterceptors.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/LogAwareKafkaTemplate.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/HashMapDeserializer.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/ISTTimeZoneHashMapDeserializer.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/serializer/ISTTimeZoneJsonSerializer.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomBindingResultExceprion.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomException.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/Error.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorQueueContract.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorRes.java create mode 100644 core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ServiceCallException.java create mode 100644 core/libraries/ifix-tracer/src/main/resources/logback-spring-json.xml.bak create mode 100644 core/libraries/ifix-tracer/src/main/resources/logback-spring.xml create mode 100644 core/libraries/ifix-tracer/src/main/resources/tracer.properties create mode 100644 core/libraries/ifix-tracer/src/test/java/org/egov/ObjectMapperTest.java create mode 100644 core/libraries/ifix-tracer/src/test/java/org/egov/Resources.java create mode 100644 core/libraries/ifix-tracer/src/test/java/org/egov/tracer/kafka/KafkaListenerLoggingAspectTest.java create mode 100644 core/libraries/ifix-tracer/src/test/resources/requestBodyWithCorrelationIdPresentInRequestInfo.json create mode 100644 core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutCorrelationIdPresentInRequestInfo.json create mode 100644 core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutRequestInfoField.json create mode 100644 core/libraries/ifix-tracer/verify.sh diff --git a/build/build-config.yml b/build/build-config.yml index 3f2afbda..d6a96f35 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -12,6 +12,10 @@ config: build: - work-dir: "core/libraries/ifix-services-common" image-name: "ifix-services-common" + - name: "builds/iFix/core/libraries/ifix-tracer" + build: + - work-dir: "core/libraries/ifix-tracer" + image-name: "ifix-tracer" - name: "builds/iFix/domain-services/ifix-master-data-service" build: - work-dir: "domain-services/ifix-master-data-service" diff --git a/core/libraries/ifix-services-common/.gitignore b/core/libraries/ifix-services-common/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/core/libraries/ifix-services-common/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/core/libraries/ifix-services-common/Dockerfile b/core/libraries/ifix-services-common/Dockerfile new file mode 100644 index 00000000..cd50dd41 --- /dev/null +++ b/core/libraries/ifix-services-common/Dockerfile @@ -0,0 +1,17 @@ +FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +ARG WORK_DIR +ARG nexusUsername +ARG nexusPassword +WORKDIR /app +# copy the project files +COPY ${WORK_DIR}/pom.xml ./pom.xml +COPY ${WORK_DIR}/settings.xml ./settings.xml +# COPY build/maven/settings.xml ./settings.xml +# COPY build/maven/start.sh ./start.sh +COPY ${WORK_DIR}/src ./src +# not useful for stateless builds +# RUN mvn -B dependency:go-offline +RUN cd ${WORK_DIR} \ + && mvn -B -f /app/pom.xml test verify deploy -s settings.xml \ + -Dnexus.user=${nexusUsername} -Dnexus.password=${nexusPassword} +FROM scratch \ No newline at end of file diff --git a/core/libraries/ifix-services-common/pom.xml b/core/libraries/ifix-services-common/pom.xml new file mode 100644 index 00000000..47b7361a --- /dev/null +++ b/core/libraries/ifix-services-common/pom.xml @@ -0,0 +1,73 @@ + + + 4.0.0 + org.egov.services + ifix-services-common + ifix-services-common + 0.0.1-SNAPSHOT + Shared classes among services + + + UTF-8 + 1.8 + UTF-8 + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org + eGov ERP Snapshots Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + + + + org.projectlombok + lombok + 1.16.12 + true + + + com.fasterxml.jackson.core + jackson-annotations + 2.8.7 + + + jakarta.validation + jakarta.validation-api + 2.0.2 + compile + + + + + + + maven-compiler-plugin + + 8 + 8 + + + + maven-source-plugin + + + attach-sources + + jar + + + + + + + diff --git a/core/libraries/ifix-services-common/settings.xml b/core/libraries/ifix-services-common/settings.xml new file mode 100644 index 00000000..40c8ed5c --- /dev/null +++ b/core/libraries/ifix-services-common/settings.xml @@ -0,0 +1,23 @@ + + + + + nexus + central + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + + + repo.digit.org + ${nexus.user} + ${nexus.password} + + + + com.versioneye + + \ No newline at end of file diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/AuditDetails.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/AuditDetails.java new file mode 100644 index 00000000..e0e5bd11 --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/AuditDetails.java @@ -0,0 +1,19 @@ +package org.egov.common.contract; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class AuditDetails { + + private String createdBy = null; + private String lastModifiedBy = null; + private Long createdTime = null; + private Long lastModifiedTime = null; + +} diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/RequestHeader.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/RequestHeader.java new file mode 100644 index 00000000..e8e61290 --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/RequestHeader.java @@ -0,0 +1,21 @@ +package org.egov.common.contract.request; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class RequestHeader { + + private Long ts = null; + private String version = null; + private String msgId = null; + private UserInfo userInfo = null; + private String correlationId = null; + private String signature = null; + +} diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/UserInfo.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/UserInfo.java new file mode 100644 index 00000000..58455ee2 --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/request/UserInfo.java @@ -0,0 +1,21 @@ +package org.egov.common.contract.request; + +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class UserInfo { + + private String uuid = null; + private List roles = null; + private List tenants = null; + private Object attributes = null; + +} diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/Error.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/Error.java new file mode 100644 index 00000000..949fd069 --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/Error.java @@ -0,0 +1,18 @@ +package org.egov.common.contract.response; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class Error { + + private String code = null; + private String message = null; + private String description = null; + +} diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ErrorResponse.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ErrorResponse.java new file mode 100644 index 00000000..aab717f6 --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ErrorResponse.java @@ -0,0 +1,19 @@ +package org.egov.common.contract.response; + +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class ErrorResponse { + + private ResponseHeader responseHeader = null; + private List errors = null; + +} diff --git a/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ResponseHeader.java b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ResponseHeader.java new file mode 100644 index 00000000..0024575c --- /dev/null +++ b/core/libraries/ifix-services-common/src/main/java/org/egov/common/contract/response/ResponseHeader.java @@ -0,0 +1,21 @@ +package org.egov.common.contract.response; + +import lombok.*; + +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class ResponseHeader { + + private Long ts = null; + private String correlationId = null; + private String msgId = null; + private String status = null; + private String signature = null; + private String version = null; + +} diff --git a/core/libraries/ifix-tracer/.gitignore b/core/libraries/ifix-tracer/.gitignore new file mode 100644 index 00000000..2af7cefb --- /dev/null +++ b/core/libraries/ifix-tracer/.gitignore @@ -0,0 +1,24 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +nbproject/private/ +build/ +nbbuild/ +dist/ +nbdist/ +.nb-gradle/ \ No newline at end of file diff --git a/core/libraries/ifix-tracer/Dockerfile b/core/libraries/ifix-tracer/Dockerfile new file mode 100644 index 00000000..cd50dd41 --- /dev/null +++ b/core/libraries/ifix-tracer/Dockerfile @@ -0,0 +1,17 @@ +FROM egovio/alpine-maven-builder-jdk-8:1-master-NA-6036091e AS build +ARG WORK_DIR +ARG nexusUsername +ARG nexusPassword +WORKDIR /app +# copy the project files +COPY ${WORK_DIR}/pom.xml ./pom.xml +COPY ${WORK_DIR}/settings.xml ./settings.xml +# COPY build/maven/settings.xml ./settings.xml +# COPY build/maven/start.sh ./start.sh +COPY ${WORK_DIR}/src ./src +# not useful for stateless builds +# RUN mvn -B dependency:go-offline +RUN cd ${WORK_DIR} \ + && mvn -B -f /app/pom.xml test verify deploy -s settings.xml \ + -Dnexus.user=${nexusUsername} -Dnexus.password=${nexusPassword} +FROM scratch \ No newline at end of file diff --git a/core/libraries/ifix-tracer/README.md b/core/libraries/ifix-tracer/README.md new file mode 100644 index 00000000..88764941 --- /dev/null +++ b/core/libraries/ifix-tracer/README.md @@ -0,0 +1,122 @@ +# iFix-Tracer + +### Distributed tracing library + +Correlation id and logging support addons to Spring Web and Spring Kafka. + +#### Features supported + +###### Logging of the below mentioned scenarios - + +- Incoming http request URI, query strings and payload. +- Message payload and topic name when pushing message to Kafka. +- Success & failure response from Kafka when pushing of message fails. +- Message payload and topic name for messages received by Kafka consumer using the KafkaListener annotation. +- Outgoing http request URI and payload along with response code and response body when using RestTemplate. +- Format validator & error queue + +###### Format Validator & Error Queue + +- Format validator & ErrorQ are the part of new version of tracer library +- Include Version 1.1.3 in pom.xml + +###### # How to use it: + +- Do not keep the "bindingresult" as an argument in the controller + eg. ``` throw new CustomBindingResultExceprion(bindingResult); ``` + +- throw customException which takes 2 arguments ErrorCode & ErrorMsg. + eg. ``` throw new CustomException("usr_001","invalid user role"); ``` +- Throw customException if you want to throw multiple errors at a time by passing an argument Map.Map + key is representing the ErrorCode & value is ErrorMsg. eg. + +``` +Map map = new HashMap<>(); + map.put("asset_001", "Invalid user"); + map.put("asset_002", "invalid name"); + + throw new CustomException(map); +``` + +###### Toggle logging detail - + +The logging of the http request/response body and Kakfa message body can be toggled on/off using +"tracer.detailed.tracing.enabled" application property. + +###### Correlation id retrieval and forwarding - + +The library takes care of retrieving the correlation id from - + +- Incoming http request body or header +- Kafka message payload + +For an outgoing http request the correlation id is sent as a custom request header "x-correlation-id". + +###### Setting the correlation id in the MDC - + +Given the library takes care of placing the correlation id into the MDC, any custom logging done in the application +would seamlessly include the correlation id in the log message. + +Note - See the "logging.pattern" mentioned in the "Tracer integration" section. + +#### Steps to integrate Tracer to your Spring application - + +- In the pom.xml add the below repository section + + ``` + + + repo.egovernments.org + eGov ERP Releases Repository + http://repo.egovernments.org/nexus/content/repositories/releases/ + + + ``` + +- In the pom.xml add the below dependency and replace version accordingly. + + ``` + + org.egov.services + tracer + X.Y.Z + + ``` + +- Add the below entry to application.properties + + ``` + logging.pattern.console=%clr(%X{CORRELATION_ID:-}) %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} + ``` + +- In the main Spring application class file add the below annotation to the class. + + ``` + @Import({TracerConfiguration.class}) +``` + +- To make http requests, in your class component autowire Spring's RestTemplate. +- To push messages to Kafka, in your class component autowire LogAwareKafkaTemplate. +- To receive messages via Kafka consumer annotate your bean method with KafkaListener annotation. Add the payload + annotation to the message payload parameter (any data type is supported) and topic header to the topic String + parameter. + +#### Tracer implementation details - + +- A Spring filter is used to retrieve the correlation id from the incoming http request. +- If the incoming http request is a POST and the content type is compatible with application/json then the library makes + an attempt to retrieve the correlation id from the request body. The json path searched for the correlation id are + RequestInfo.correlationId and requestInfo.correlationId. +- If the correlation id is not present in the request body or the http verb is not POST or the content type is not json + compatible then an attempt is made to retrieve the correlation id from the http request header "x-correlation-id". +- If the correlation id is not present in the request body or header then a new correlation id (UUID v4) is generated. +- For the RestTemplate an interceptor is used for adding the correlation id as a custom header to the outgoing request, + logging the corresponding request and response sent and received. +- A subclass of Spring's RestTemplate is registered as a Spring bean to perform the correlation id forwarding and + logging. +- The LogAwareKafkaTemplate is a wrapper Spring bean class for Spring Kafka's KafkaTemplate that performs the logging of + messages sent to Kafka. +- For a Kafka consumer implemented using Spring Kafka's KafkaListener annotation an AspectJ's aspect is used to log and + retrieve the correlation id from the received payload. +- The correlation id retrieved via the filter or aspect is then stored in a thread local variable to forward as + necessary. \ No newline at end of file diff --git a/core/libraries/ifix-tracer/pom.xml b/core/libraries/ifix-tracer/pom.xml new file mode 100644 index 00000000..4f9fd2a6 --- /dev/null +++ b/core/libraries/ifix-tracer/pom.xml @@ -0,0 +1,145 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + ifix-tracer + Assist in tracing http and message queue flows + + + repo.digit.org + eGov ERP Snapshots Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + + UTF-8 + 1.8 + UTF-8 + 1.18.8 + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.kafka + spring-kafka + + + org.apache.kafka + kafka-clients + + + org.projectlombok + lombok + true + + + commons-io + commons-io + 2.5 + + + org.egov.services + ifix-services-common + 0.0.1-SNAPSHOT + + + com.jayway.jsonpath + json-path + 2.2.0 + + + org.aspectj + aspectjweaver + 1.8.13 + + + org.springframework.boot + spring-boot-starter-actuator + + + io.opentracing.contrib + opentracing-spring-web-starter + 0.3.3 + + + io.opentracing.contrib + opentracing-spring-cloud-jdbc-starter + 0.2.1 + + + io.opentracing.contrib + opentracing-spring-jaeger-starter + 0.2.2 + + + io.jaegertracing + jaeger-client + 0.31.0 + + + net.logstash.logback + logstash-logback-encoder + 5.2 + + + ch.qos.logback + logback-classic + 1.2.3 + + + org.springframework.boot + spring-boot-starter-test + test + + + com.github.stefanbirkner + system-rules + 1.16.1 + test + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + + + + maven-source-plugin + + + attach-sources + + jar + + + + + + + diff --git a/core/libraries/ifix-tracer/settings.xml b/core/libraries/ifix-tracer/settings.xml new file mode 100644 index 00000000..40c8ed5c --- /dev/null +++ b/core/libraries/ifix-tracer/settings.xml @@ -0,0 +1,23 @@ + + + + + nexus + central + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + + + repo.digit.org + ${nexus.user} + ${nexus.password} + + + + com.versioneye + + \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/ExceptionAdvise.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/ExceptionAdvise.java new file mode 100644 index 00000000..026cd951 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/ExceptionAdvise.java @@ -0,0 +1,248 @@ +package org.egov.tracer; + +import com.fasterxml.jackson.core.JsonParseException; +import com.fasterxml.jackson.databind.JsonMappingException; +import com.jayway.jsonpath.DocumentContext; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.egov.tracer.config.TracerProperties; +import org.egov.tracer.http.filters.MultiReadRequestWrapper; +import org.egov.tracer.kafka.ErrorQueueProducer; +import org.egov.tracer.model.Error; +import org.egov.tracer.model.*; +import org.slf4j.MDC; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.core.Ordered; +import org.springframework.core.annotation.Order; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.HttpMessageNotReadableException; +import org.springframework.validation.BindException; +import org.springframework.validation.BindingResult; +import org.springframework.validation.ObjectError; +import org.springframework.web.HttpMediaTypeNotSupportedException; +import org.springframework.web.bind.MethodArgumentNotValidException; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.ResponseBody; +import org.springframework.web.client.ResourceAccessException; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import static org.egov.tracer.constants.TracerConstants.CORRELATION_ID_MDC; + + +@ControllerAdvice +@Slf4j +@Order(Ordered.LOWEST_PRECEDENCE) +@EnableConfigurationProperties({TracerProperties.class}) +public class ExceptionAdvise { + + @Value("${tracer.errors.provideExceptionInDetails:false}") + private boolean provideExceptionInDetails; + + @Autowired + private ErrorQueueProducer errorQueueProducer; + + @Autowired + private TracerProperties tracerProperties; + + @ExceptionHandler(value = Exception.class) + @ResponseBody + public ResponseEntity exceptionHandler(HttpServletRequest request, Exception ex) { + + String contentType = request.getContentType(); + boolean isJsonContentType = (contentType != null && contentType.toLowerCase().contains("application/json")); + log.error("Exception caught in tracer ", ex); + String body = ""; + + try { + if (request instanceof MultiReadRequestWrapper) { + ServletInputStream stream = request.getInputStream(); + body = IOUtils.toString(stream, "UTF-8"); + } else + body = "Unable to retrieve request body"; + + } catch (IOException ignored) { + body = "Unable to retrieve request body"; + } + + ErrorRes errorRes = new ErrorRes(); + List errors = new ArrayList<>(); + + try { + if (ex instanceof HttpMediaTypeNotSupportedException) { + errorRes.setErrors(new ArrayList<>(Collections.singletonList(new Error("UnsupportedMediaType", "An " + + "unsupported media Type was used - " + request.getContentType(), null, null)))); + } else if (ex instanceof ResourceAccessException) { + Error err = new Error(); + err.setCode("ResourceAccessError"); + err.setMessage("An error occurred while accessing a underlying resource"); + errors.add(err); + errorRes.setErrors(errors); + } else if (ex instanceof HttpMessageNotReadableException) { + Error err = new Error(); + String message = ex.getMessage(); + + if (ex.getCause() instanceof JsonMappingException) { + + Pattern pattern = Pattern.compile("(.+)Can not deserialize instance of ([a-z]+\\.){1,}(?[^ ]+).*\\[\"(?[^\"]+)\"\\].*", + Pattern.CASE_INSENSITIVE | Pattern.DOTALL); + Matcher match = pattern.matcher(message); + boolean matched = match.find(); + if (matched) { + err.setMessage("Failed to parse field - " + match.group("objectname") + ". Expected type is " + match.group("objecttype")); + } else { + err.setMessage("Failed to deserialize certain JSON fields"); + } + + err.setCode("JsonMappingException"); + + } else if (ex.getCause() instanceof JsonParseException) { + err.setCode("JsonParseException"); + message = ex.getCause().getMessage().replaceAll("Source: [^;]+; ", "").replaceAll(" \\(code \\d+\\)", "").replaceAll("\\n", ""); + err.setMessage(message); + } else { + try { + err.setMessage("JSON body has errors or is missing"); + JsonPath.parse(request).json(); + } catch (Exception jsonParseException) { + log.warn("Error while parsing JSON", jsonParseException); + } + err.setCode("MissingJsonException"); + } + errors.add(err); + errorRes.setErrors(errors); + } else if (ex instanceof MethodArgumentNotValidException) { + MethodArgumentNotValidException argumentNotValidException = (MethodArgumentNotValidException) ex; + errorRes.setErrors(getBindingErrors(argumentNotValidException.getBindingResult(), errors)); + + } else if (ex instanceof CustomBindingResultExceprion) { + CustomBindingResultExceprion customBindingResultExceprion = (CustomBindingResultExceprion) ex; + errorRes.setErrors(getBindingErrors(customBindingResultExceprion.getBindingResult(), errors)); + } else if (ex instanceof CustomException) { + CustomException customException = (CustomException) ex; + populateCustomErrors(customException, errors); + errorRes.setErrors(errors); + } else if (ex instanceof ServiceCallException) { + ServiceCallException serviceCallException = (ServiceCallException) ex; + sendErrorMessage(body, ex, request.getRequestURL().toString(), errorRes, isJsonContentType); + DocumentContext documentContext = JsonPath.parse(serviceCallException.getError()); + LinkedHashMap linkedHashMap = documentContext.json(); + return new ResponseEntity<>(linkedHashMap, HttpStatus.BAD_REQUEST); + + } else if (ex instanceof MissingServletRequestParameterException) { + MissingServletRequestParameterException exception = (MissingServletRequestParameterException) ex; + Error error = new Error(); + error.setCode(""); + error.setMessage(exception.getMessage()); + //error.setDescription(exception.getCause().toString()); + List params = new ArrayList<>(); + params.add(exception.getParameterName()); + error.setParams(params); + errors.add(error); + errorRes.setErrors(errors); + } else if (ex instanceof BindException) { + BindException bindException = (BindException) ex; + + errorRes.setErrors(getBindingErrors(bindException.getBindingResult(), errors)); + + //errorRes.setErrors(errors); + } + + String exceptionName = ex.getClass().getSimpleName(); + String exceptionMessage = ex.getMessage(); + + if (errorRes.getErrors() == null || errorRes.getErrors().size() == 0) { + errorRes.setErrors(new ArrayList<>(Collections.singletonList(new Error(exceptionName, "An unhandled exception occurred on the server", exceptionMessage, null)))); + } else if (provideExceptionInDetails && errorRes.getErrors() != null && errorRes.getErrors().size() > 0) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + errorRes.getErrors().get(0).setDescription(sw.toString()); + } + + sendErrorMessage(body, ex, request.getRequestURL().toString(), errorRes, isJsonContentType); + } catch (Exception tracerException) { + log.error("Error in tracer", tracerException); + errorRes.setErrors(new ArrayList<>(Collections.singletonList(new Error("TracerException", "An unhandled exception occurred in tracer handler", null, null)))); + } + return new ResponseEntity<>(errorRes, HttpStatus.BAD_REQUEST); + } + + private List getBindingErrors(BindingResult bindingResult, List errors) { + + List objectErrors = bindingResult.getAllErrors(); + + for (ObjectError objectError : objectErrors) { + Error error = new Error(); + String[] codes = objectError.getCodes(); + error.setCode(codes[0]); + error.setMessage(objectError.getDefaultMessage()); + errors.add(error); + } + + return errors; + } + + private void populateCustomErrors(CustomException customException, List errors) { + Map map = customException.getErrors(); + if (map != null && !map.isEmpty()) { + for (Map.Entry entry : map.entrySet()) { + Error error = new Error(); + error.setCode(entry.getKey()); + error.setMessage(entry.getValue()); + errors.add(error); + } + } else { + Error error = new Error(); + error.setCode(customException.getCode()); + error.setMessage(customException.getMessage()); + errors.add(error); + } + + } + + void sendErrorMessage(String body, Exception ex, String source, ErrorRes errorRes, boolean isJsonContentType) { + DocumentContext documentContext; + + if (tracerProperties.isErrorsPublish()) { + Object requestBody = body; + if (isJsonContentType) { + try { + documentContext = JsonPath.parse(body); + requestBody = documentContext.json(); + } catch (Exception exception) { + requestBody = body; + } + } + + StackTraceElement elements[] = ex.getStackTrace(); + + ErrorQueueContract errorQueueContract = ErrorQueueContract.builder() + .id(UUID.randomUUID().toString()) + .correlationId(MDC.get(CORRELATION_ID_MDC)) + .body(requestBody) + .source(source) + .ts(new Date().getTime()) + .errorRes(errorRes) + .exception(Arrays.asList(elements)) + .message(ex.getMessage()) + .build(); + + errorQueueProducer.sendMessage(errorQueueContract); + } + + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/KafkaConsumerErrorHandler.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/KafkaConsumerErrorHandler.java new file mode 100644 index 00000000..8fbdf4ca --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/KafkaConsumerErrorHandler.java @@ -0,0 +1,37 @@ +package org.egov.tracer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.kafka.listener.LoggingErrorHandler; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +@Component +@Slf4j +public class KafkaConsumerErrorHandler extends LoggingErrorHandler { + + @Autowired + private ExceptionAdvise exceptionAdvise; + + @Value("${tracer.errorsPublish}") + private boolean sendErrorsToKafka; + + @Override + public void handle(Exception thrownException, ConsumerRecord record) { + if (sendErrorsToKafka) { + log.error("Error while processing1: " + ObjectUtils.nullSafeToString(record), thrownException); + ObjectMapper objectMapper = new ObjectMapper(); + String body = null; + try { + body = objectMapper.writeValueAsString(record.value()); + } catch (Exception ex) { + log.error("KafkaConsumerErrorHandller Kafka consumer can not parse json data"); + ex.printStackTrace(); + } + exceptionAdvise.sendErrorMessage(body, thrownException, record.topic(), null, false); + } + } +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/ObjectMapperFactory.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/ObjectMapperFactory.java new file mode 100644 index 00000000..cefddc59 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/ObjectMapperFactory.java @@ -0,0 +1,25 @@ +package org.egov.tracer.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.core.env.Environment; + +import java.util.TimeZone; + +import static org.egov.tracer.constants.TracerConstants.TIME_ZONE_PROPERTY; + +public class ObjectMapperFactory { + + private TracerProperties tracerProperties; + + private ObjectMapper objectMapper; + + public ObjectMapperFactory(TracerProperties tracerProperties, Environment environment) { + this.tracerProperties = tracerProperties; + this.objectMapper = new ObjectMapper(); + objectMapper.setTimeZone(TimeZone.getTimeZone(environment.getProperty(TIME_ZONE_PROPERTY, "UTC"))); + } + + public ObjectMapper getObjectMapper() { + return objectMapper; + } +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/OpenTracingConfiguration.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/OpenTracingConfiguration.java new file mode 100644 index 00000000..9194b1fa --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/OpenTracingConfiguration.java @@ -0,0 +1,81 @@ +package org.egov.tracer.config; + +import io.opentracing.Span; +import io.opentracing.contrib.spring.tracer.configuration.TracerAutoConfiguration; +import io.opentracing.contrib.web.servlet.filter.ServletFilterSpanDecorator; +import org.slf4j.MDC; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.util.ArrayList; +import java.util.List; + +import static org.egov.tracer.constants.TracerConstants.CORRELATION_ID_MDC; +import static org.egov.tracer.constants.TracerConstants.CORRELATION_ID_OPENTRACING_FORMAT; + +@Configuration +@ConditionalOnWebApplication +@AutoConfigureAfter({TracerAutoConfiguration.class}) +@ConditionalOnClass({WebMvcConfigurerAdapter.class}) +@ConditionalOnProperty( + name = {"tracer.opentracing.enabled"}, + havingValue = "true", + matchIfMissing = false +) +public class OpenTracingConfiguration { + + /** + * Jaeger Tracer instance configured via environment variables + * + * @return Tracer implementation + */ + @Bean + public io.opentracing.Tracer jaegerTracer() { + return io.jaegertracing.Configuration.fromEnv() + .getTracer(); + } + + /** + * Use span decorator to add a correlation id span tag + *

+ * Filter order configured to run after Tracer Filter + * + * @return span decorators + */ + @Bean + public List spanDecorator() { + List decorators = new ArrayList<>(); + decorators.add(ServletFilterSpanDecorator.STANDARD_TAGS); + decorators.add(new ServletFilterSpanDecorator() { + @Override + public void onRequest(HttpServletRequest httpServletRequest, Span span) { + span.setTag(CORRELATION_ID_OPENTRACING_FORMAT, MDC.get(CORRELATION_ID_MDC)); + } + + @Override + public void onResponse(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Span span) { + + } + + @Override + public void onError(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Throwable throwable, Span span) { + + } + + @Override + public void onTimeout(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, long l, Span span) { + + } + }); + + return decorators; + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerConfiguration.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerConfiguration.java new file mode 100644 index 00000000..28266bd8 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerConfiguration.java @@ -0,0 +1,78 @@ +package org.egov.tracer.config; + +import io.opentracing.noop.NoopTracerFactory; +import org.egov.tracer.http.RestTemplateLoggingInterceptor; +import org.egov.tracer.http.filters.TracerFilter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.boot.context.properties.EnableConfigurationProperties; +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.*; +import org.springframework.core.env.Environment; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +@Configuration +@EnableAspectJAutoProxy +@ComponentScan(basePackages = {"org.egov.tracer"}) +@PropertySource("classpath:tracer.properties") +@EnableConfigurationProperties({TracerProperties.class}) +@Import(OpenTracingConfiguration.class) +public class TracerConfiguration { + + @Bean + public ObjectMapperFactory objectMapperFactory(TracerProperties tracerProperties, Environment environment) { + return new ObjectMapperFactory(tracerProperties, environment); + } + + @Bean(name = "logAwareRestTemplate") + public RestTemplate logAwareRestTemplate(TracerProperties tracerProperties) { + SimpleClientHttpRequestFactory requestFactory = new SimpleClientHttpRequestFactory(); + requestFactory.setOutputStreaming(false); + RestTemplate restTemplate = + new RestTemplate(new BufferingClientHttpRequestFactory(requestFactory)); + restTemplate.setInterceptors(Collections.singletonList(new RestTemplateLoggingInterceptor(tracerProperties))); + return restTemplate; + } + + /** + * Configure tracer filter with order one + * + * @param objectMapperFactory Object mapper + * @param tracerProperties configuration for the filter + * @return Filter + */ + @Bean + @ConditionalOnProperty(name = "tracer.filter.enabled", + havingValue = "true", matchIfMissing = true) + public FilterRegistrationBean tracerFilter(ObjectMapperFactory objectMapperFactory, + TracerProperties tracerProperties) { + final TracerFilter tracerFilter = new TracerFilter(tracerProperties, objectMapperFactory); + FilterRegistrationBean registration = new FilterRegistrationBean(tracerFilter); + registration.addUrlPatterns("/*"); + registration.setName("TracerFilter"); + registration.setOrder(1); + return registration; + } + + /** + * Disable open tracing by injecting a Noop + * + * @return Noop tracer + */ + @Bean + @ConditionalOnProperty( + name = {"tracer.opentracing.enabled"}, + havingValue = "false", + matchIfMissing = true + ) + public io.opentracing.Tracer tracer() { + return NoopTracerFactory.create(); + } + + +} + + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerProperties.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerProperties.java new file mode 100644 index 00000000..3d8cb4b5 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/config/TracerProperties.java @@ -0,0 +1,31 @@ +package org.egov.tracer.config; + +import lombok.Data; +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.context.annotation.Configuration; + +@Data +@ConfigurationProperties("tracer") +@Configuration +public class TracerProperties { + + // Enable request body and query parameters logging + private boolean requestLoggingEnabled; + + // Enable kafka message body logging on send + private boolean kafkaMessageLoggingEnabled; + + // Enable request and response body logging on all rest template calls + private boolean restTemplateDetailedLoggingEnabled; + + // Enable errors publishing on a kafka topic + private boolean errorsPublish; + + // Topic to which errors need to be published + private String errorsTopic; + + // Exclusion list for tracer filter + private String filterSkipPattern; + +} + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/constants/TracerConstants.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/constants/TracerConstants.java new file mode 100644 index 00000000..31927f94 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/constants/TracerConstants.java @@ -0,0 +1,15 @@ +package org.egov.tracer.constants; + +public class TracerConstants { + + public static final String CORRELATION_ID_HEADER = "x-correlation-id"; + public static final String CORRELATION_ID_FIELD_NAME = "correlationId"; + public static final String CORRELATION_ID_MDC = "CORRELATION_ID"; + public static final String CORRELATION_ID_OPENTRACING_FORMAT = "correlation.id"; + public static final String TIME_ZONE_PROPERTY = "app.timezone"; + public static final String REQUEST_HEADER_FIELD_NAME_IN_JAVA_CLASS_CASE = "RequestHeader"; + public static final String REQUEST_HEADER_IN_CAMEL_CASE = "requestHeader"; + + private TracerConstants() { + } +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/HttpUtils.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/HttpUtils.java new file mode 100644 index 00000000..88baafbc --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/HttpUtils.java @@ -0,0 +1,18 @@ +package org.egov.tracer.http; + +import org.springframework.http.HttpHeaders; + +public class HttpUtils { + + private static final String PASS_THROUGH_GATEWAY_HEADER_NAME = "x-pass-through-gateway"; + + private HttpUtils() { + } + + public static boolean isInterServiceCall(HttpHeaders headers) { + String x_pass_through_gatewayStr = headers.getFirst(PASS_THROUGH_GATEWAY_HEADER_NAME); + + return x_pass_through_gatewayStr == null || !x_pass_through_gatewayStr.equalsIgnoreCase("true"); + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/RestTemplateLoggingInterceptor.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/RestTemplateLoggingInterceptor.java new file mode 100644 index 00000000..c97ca189 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/RestTemplateLoggingInterceptor.java @@ -0,0 +1,114 @@ +package org.egov.tracer.http; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.egov.tracer.config.TracerProperties; +import org.slf4j.MDC; +import org.springframework.http.HttpMessage; +import org.springframework.http.HttpRequest; +import org.springframework.http.MediaType; +import org.springframework.http.client.ClientHttpRequestExecution; +import org.springframework.http.client.ClientHttpRequestInterceptor; +import org.springframework.http.client.ClientHttpResponse; + +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +import static org.egov.tracer.constants.TracerConstants.CORRELATION_ID_HEADER; +import static org.egov.tracer.constants.TracerConstants.CORRELATION_ID_MDC; + +@Slf4j +public class RestTemplateLoggingInterceptor implements ClientHttpRequestInterceptor { + + private static final String REQUEST_MESSAGE_WITH_BODY = "Sending request to {} with verb {} with body {}"; + private static final String REQUEST_MESSAGE = "Sending request to {} with verb {}"; + private static final String RESPONSE_MESSAGE_WITH_BODY = "Received from {} response code {} and body {}: "; + private static final String RESPONSE_MESSAGE = "Received response from {}"; + private static final String FAILED_RESPONSE_MESSAGE = "Received error response from %s"; + private static final String UTF_8 = "UTF-8"; + private static final String RESPONSE_BODY_ERROR_MESSAGE = "Error reading response body"; + private static final String EMPTY_BODY = ""; + private static final List JSON_MEDIA_TYPES = + Arrays.asList(MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE); + + private TracerProperties tracerProperties; + + public RestTemplateLoggingInterceptor(TracerProperties tracerProperties) { + this.tracerProperties = tracerProperties; + } + + /** + * Intercept all rest template calls + * - Add correlation id header from MDC + * - Log request and responses based on config + * + * @param request being made + * @param body of the request + * @param execution execute the rest template call + * @return response of the rest call + * @throws IOException + */ + @Override + public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException { + try { + request.getHeaders().add(CORRELATION_ID_HEADER, MDC.get(CORRELATION_ID_MDC)); + logRequest(request, body); + + final ClientHttpResponse rawResponse = execution.execute(request, body); + + if (tracerProperties.isRestTemplateDetailedLoggingEnabled() && isBodyCompatibleForParsing(request)) { + logResponse(rawResponse, request); + } else { + log.info(RESPONSE_MESSAGE, request.getURI()); + } + return rawResponse; + } catch (Exception e) { + log.warn(String.format(FAILED_RESPONSE_MESSAGE, request.getURI()), e); + throw e; + } + } + + private void logResponse(ClientHttpResponse response, HttpRequest httpRequest) throws IOException { + + if (tracerProperties.isRestTemplateDetailedLoggingEnabled() && isBodyCompatibleForParsing(httpRequest)) { + String body = getBodyString(response); + log.info(RESPONSE_MESSAGE_WITH_BODY, httpRequest.getURI(), response.getStatusCode(), body); + } else { + log.info(RESPONSE_MESSAGE, httpRequest.getURI()); + } + + } + + private void logRequest(HttpRequest httpRequest, byte[] body) { + if (tracerProperties.isRestTemplateDetailedLoggingEnabled() && isBodyCompatibleForParsing(httpRequest)) { + log.info(REQUEST_MESSAGE_WITH_BODY, httpRequest.getURI(), httpRequest.getMethod().name(), getBody(body)); + } else { + log.info(REQUEST_MESSAGE, httpRequest.getURI(), httpRequest.getMethod().name()); + } + } + + + private String getBody(byte[] body) { + return body == null ? EMPTY_BODY : new String(body); + } + + private boolean isBodyCompatibleForParsing(HttpMessage httpMessage) { + final MediaType contentType = httpMessage.getHeaders().getContentType(); + return contentType != null && JSON_MEDIA_TYPES.contains(contentType.toString()); + } + + private String getBodyString(ClientHttpResponse response) { + try { + if (response != null && response.getBody() != null) { + return IOUtils.toString(response.getBody(), UTF_8); + } else { + return EMPTY_BODY; + } + } catch (IOException e) { + log.error(RESPONSE_BODY_ERROR_MESSAGE, e); + return EMPTY_BODY; + } + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/MultiReadRequestWrapper.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/MultiReadRequestWrapper.java new file mode 100644 index 00000000..a476f2f7 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/MultiReadRequestWrapper.java @@ -0,0 +1,81 @@ +package org.egov.tracer.http.filters; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; + +import javax.servlet.ReadListener; +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletRequestWrapper; +import java.io.*; + +@Slf4j +public class MultiReadRequestWrapper extends HttpServletRequestWrapper { + + private ByteArrayOutputStream cachedBytes; + + MultiReadRequestWrapper(HttpServletRequest request) { + super(request); + } + + @Override + public ServletInputStream getInputStream() throws IOException { + if (cachedBytes == null) + cacheInputStream(); + + return new CachedServletInputStream(); + } + + public void update(ByteArrayOutputStream newBytes) { + this.cachedBytes = newBytes; + } + +// @Override +// public int getContentLength() { +// return this.cachedBytes.size(); +// } +// +// @Override +// public long getContentLengthLong() { +// return this.cachedBytes.size(); +// } + + @Override + public BufferedReader getReader() throws IOException { + return new BufferedReader(new InputStreamReader(getInputStream())); + } + + private void cacheInputStream() throws IOException { + cachedBytes = new ByteArrayOutputStream(); + IOUtils.copy(super.getInputStream(), cachedBytes); + } + + public class CachedServletInputStream extends ServletInputStream { + private ByteArrayInputStream input; + + CachedServletInputStream() { + input = new ByteArrayInputStream(cachedBytes.toByteArray()); + } + + @Override + public boolean isFinished() { + return input.available() != 0; + } + + @Override + public boolean isReady() { + return true; + } + + @Override + public void setReadListener(ReadListener readListener) { + + } + + @Override + public int read() throws IOException { + return input.read(); + } + } +} + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/TracerFilter.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/TracerFilter.java new file mode 100644 index 00000000..f5461574 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/http/filters/TracerFilter.java @@ -0,0 +1,192 @@ +package org.egov.tracer.http.filters; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.egov.tracer.config.ObjectMapperFactory; +import org.egov.tracer.config.TracerProperties; +import org.slf4j.MDC; +import org.springframework.http.MediaType; + +import javax.servlet.*; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import java.io.IOException; +import java.util.*; +import java.util.regex.Pattern; + +import static java.util.Objects.isNull; +import static org.egov.tracer.constants.TracerConstants.*; +import static org.springframework.util.StringUtils.isEmpty; + +@Slf4j +public class TracerFilter implements Filter { + + private static final List JSON_MEDIA_TYPES = + Arrays.asList(MediaType.APPLICATION_JSON_UTF8_VALUE, MediaType.APPLICATION_JSON_VALUE); + private static final String POST = "POST"; + private static final String REQUEST_BODY_LOG_MESSAGE = "Request body - {}"; + private static final String FAILED_TO_LOG_REQUEST_MESSAGE = "Failed to log request body"; + private static final String UTF_8 = "UTF-8"; + private static final String REQUEST_URI_LOG_MESSAGE = "Received request URI: {} "; + private static final String REQUEST_PARAMS_LOG_MESSAGE = "Request Query params: {} "; + private static final String LOG_RESPONSE_CODE_MESSAGE = "Response code sent: {}"; + + private final ObjectMapper objectMapper; + private TracerProperties tracerProperties; + private Pattern skipPattern; + + public TracerFilter(TracerProperties tracerProperties, ObjectMapperFactory objectMapperFactory) { + this.tracerProperties = tracerProperties; + this.objectMapper = objectMapperFactory.getObjectMapper(); + this.skipPattern = isNull(tracerProperties.getFilterSkipPattern()) ? null : + Pattern.compile(tracerProperties.getFilterSkipPattern()); + } + + @Override + public void init(FilterConfig filterConfig) { + + } + + /** + * Cache the request for future body reads in case the body is compatible [json] + * Retrieves correlation id + * - From header + * - if not exists, attempt to retrieve from body RequestHeader + * - if not exists, generate a uuid + *

+ * Set correlation id in MDC for future use, like logging etc + * Log Request and Response depending on configuration + * + * @param servletRequest HTTP request + * @param servletResponse HTTP response + * @param filterChain pass control to the chain + * @throws IOException + * @throws ServletException + */ + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + String correlationId = null; + HttpServletRequest httpRequest = (HttpServletRequest) servletRequest; + + if (!this.isTraced(httpRequest)) { + filterChain.doFilter(httpRequest, servletResponse); + } else { + + if (isBodyCompatibleForParsing(httpRequest)) { + final MultiReadRequestWrapper wrappedRequest = new MultiReadRequestWrapper(httpRequest); + correlationId = getCorrelationId(wrappedRequest); + MDC.put(CORRELATION_ID_MDC, correlationId); + logRequestURI(httpRequest); + + if (tracerProperties.isRequestLoggingEnabled()) { + logRequestBodyAndParams(wrappedRequest); + } + + filterChain.doFilter(wrappedRequest, servletResponse); + + } else { + correlationId = getCorrelationId(httpRequest); + MDC.put(CORRELATION_ID_MDC, correlationId); + logRequestURI(httpRequest); + filterChain.doFilter(httpRequest, servletResponse); + } + + logResponse(servletResponse); + } + } + + @Override + public void destroy() { + MDC.clear(); + } + + private boolean isTraced(HttpServletRequest httpServletRequest) { + if (this.skipPattern != null) { + String url = httpServletRequest.getRequestURI().substring(httpServletRequest.getContextPath().length()); + return !this.skipPattern.matcher(url).matches(); + } else { + return true; + } + } + + private void logResponse(ServletResponse servletResponse) { + HttpServletResponse httpServletResponse = (HttpServletResponse) servletResponse; + log.info(LOG_RESPONSE_CODE_MESSAGE, httpServletResponse.getStatus()); + } + + private void logRequestURI(HttpServletRequest httpRequest) { + String url = httpRequest.getRequestURL().toString(); + log.info(REQUEST_URI_LOG_MESSAGE, url); + } + + private String getCorrelationId(HttpServletRequest httpRequest) { + String correlationId = getCorrelationIdFromHeader(httpRequest); + + if (isNull(correlationId) && httpRequest instanceof MultiReadRequestWrapper) { + correlationId = getCorrelationIdFromBody(httpRequest); + } + + if (isNull(correlationId)) + correlationId = getRandomCorrelationId(); + + return correlationId; + + } + + private boolean isBodyCompatibleForParsing(HttpServletRequest httpRequest) { + return POST.equals(httpRequest.getMethod()) + && JSON_MEDIA_TYPES.contains(httpRequest.getContentType()); + } + + + private void logRequestBodyAndParams(HttpServletRequest requestWrapper) { + try { + final String requestBody = IOUtils.toString(requestWrapper.getInputStream(), UTF_8); + String requestParams = requestWrapper.getQueryString(); + + if (!isEmpty(requestParams)) + log.info(REQUEST_PARAMS_LOG_MESSAGE, requestParams); + + if (!isEmpty(requestBody)) + log.info(REQUEST_BODY_LOG_MESSAGE, requestBody); + + } catch (IOException e) { + log.error(FAILED_TO_LOG_REQUEST_MESSAGE, e); + } + } + + private String getCorrelationIdFromHeader(HttpServletRequest httpRequest) { + return httpRequest.getHeader(CORRELATION_ID_HEADER); + } + + + @SuppressWarnings("unchecked") + private String getCorrelationIdFromBody(HttpServletRequest httpServletRequest) { + String correlationId = null; + try { + final HashMap requestMap = (HashMap) + objectMapper.readValue(httpServletRequest.getInputStream(), HashMap.class); + Object requestHeader = requestMap.containsKey(REQUEST_HEADER_FIELD_NAME_IN_JAVA_CLASS_CASE) ? requestMap.get + (REQUEST_HEADER_FIELD_NAME_IN_JAVA_CLASS_CASE) : requestMap.get(REQUEST_HEADER_IN_CAMEL_CASE); + + if (isNull(requestHeader)) + return null; + else { + if (requestHeader instanceof Map) { + correlationId = (String) ((Map) requestHeader).get(CORRELATION_ID_FIELD_NAME); + } + } + } catch (IOException ignored) { + } + + return correlationId; + } + + private String getRandomCorrelationId() { + return UUID.randomUUID().toString(); + } + + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/CustomKafkaTemplate.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/CustomKafkaTemplate.java new file mode 100644 index 00000000..c2e5592c --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/CustomKafkaTemplate.java @@ -0,0 +1,55 @@ +package org.egov.tracer.kafka; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Component; + + +@Component("customKafkaTemplate") +@Slf4j +public class CustomKafkaTemplate { + + private static final String KAFKA_SEND_ERROR_CODE = "EVENT_BUS_FAILURE"; + private static final String KAFKA_SEND_ERROR_MSG = "Failed to push event onto the event bus"; + private static final String KAFKA_ERROR_LOG = "Failed to push data to kafka queue"; + private KafkaTemplate kafkaTemplate; + + @Autowired + public CustomKafkaTemplate(KafkaTemplate kafkaTemplate) { + this.kafkaTemplate = kafkaTemplate; + } + + public SendResult send(String topic, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, value).get(); + return result; + } catch (Exception e) { + log.error(KAFKA_ERROR_LOG, e); + throw new CustomException(KAFKA_SEND_ERROR_CODE, KAFKA_SEND_ERROR_MSG); + } + } + + public SendResult send(String topic, K key, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, key, value).get(); + return result; + } catch (Exception e) { + log.error(KAFKA_ERROR_LOG, e); + throw new CustomException(KAFKA_SEND_ERROR_CODE, KAFKA_SEND_ERROR_MSG); + } + } + + public SendResult send(String topic, K key, int partition, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, partition, key, value).get(); + return result; + } catch (Exception e) { + log.error(KAFKA_ERROR_LOG, e); + throw new CustomException(KAFKA_SEND_ERROR_CODE, KAFKA_SEND_ERROR_MSG); + } + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/ErrorQueueProducer.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/ErrorQueueProducer.java new file mode 100644 index 00000000..f1feab4d --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/ErrorQueueProducer.java @@ -0,0 +1,42 @@ +package org.egov.tracer.kafka; + +import com.fasterxml.jackson.core.JsonProcessingException; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.common.errors.SerializationException; +import org.egov.tracer.config.ObjectMapperFactory; +import org.egov.tracer.config.TracerProperties; +import org.egov.tracer.model.ErrorQueueContract; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ErrorQueueProducer { + + @Autowired + private KafkaTemplate kafkaTemplate; + + @Autowired + private TracerProperties tracerProperties; + + @Autowired + private ObjectMapperFactory objectMapperFactory; + + public void sendMessage(ErrorQueueContract errorQueueContract) { + try { + kafkaTemplate.send(tracerProperties.getErrorsTopic(), errorQueueContract); + } catch (SerializationException serializationException) { + log.info("SerializationException exception occurred while sending exception to error queue"); + try { + kafkaTemplate.send(tracerProperties.getErrorsTopic(), objectMapperFactory.getObjectMapper().writeValueAsString + (errorQueueContract)); + } catch (JsonProcessingException e) { + log.info("exception occurred while converting ErrorQueueContract to json string"); + } + } catch (Exception ex) { + log.error("exception occurred while sending exception to error queue"); + } + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/KafkaTemplateLoggingInterceptors.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/KafkaTemplateLoggingInterceptors.java new file mode 100644 index 00000000..fb93b440 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/KafkaTemplateLoggingInterceptors.java @@ -0,0 +1,132 @@ +package org.egov.tracer.kafka; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.kafka.clients.consumer.ConsumerInterceptor; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.apache.kafka.clients.consumer.ConsumerRecords; +import org.apache.kafka.clients.consumer.OffsetAndMetadata; +import org.apache.kafka.clients.producer.ProducerInterceptor; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; +import org.apache.kafka.common.TopicPartition; +import org.slf4j.MDC; +import org.springframework.util.ObjectUtils; + +import java.util.Map; + +import static java.util.Objects.isNull; +import static org.egov.tracer.constants.TracerConstants.*; +import static org.springframework.util.StringUtils.isEmpty; + +@Slf4j +public class KafkaTemplateLoggingInterceptors implements ConsumerInterceptor, ProducerInterceptor { + + private static final String EMPTY_BODY = ""; + private static final String SEND_SUCCESS_MESSAGE = + "Sending message to topic: {}, partition: {} with key: {} ."; + private static final String BODY_JSON_SERIALIZATION_ERROR = "Serialization of body failed while attempting to log" + + " the body"; + private static final String SEND_SUCCESS_MESSAGE_WITH_BODY = + "Sending message to topic: {}, partition: {}, body: {} with key: {} ."; + private static final String SEND_FAILURE_MESSAGE = "Sending of message to topic: %s, partition %s failed."; + + private static final String RECEIVED_MESSAGE_WITH_BODY = "Received message from topic: {}, partition: {}, body: {} with key: {}"; + private static final String RECEIVED_MESSAGE = "Received message from topic: {}, partition: {}, with key: {}"; + + private final ObjectMapper objectMapper = new ObjectMapper(); + + public KafkaTemplateLoggingInterceptors() { + } + + @Override + public ConsumerRecords onConsume(ConsumerRecords consumerRecords) { + for (ConsumerRecord consumerRecord : consumerRecords) { + final String keyAsString = ObjectUtils.nullSafeToString(consumerRecord.key()); + String correlationId = getCorrelationIdFromBody(consumerRecord.value()); + + if (!isEmpty(correlationId)) + MDC.put(CORRELATION_ID_MDC, correlationId); + + if (log.isDebugEnabled()) { + final String bodyAsJsonString = getMessageBodyAsJsonString(consumerRecord.value()); + log.debug(RECEIVED_MESSAGE_WITH_BODY, consumerRecord.topic(), consumerRecord.partition(), bodyAsJsonString, + keyAsString); + } else { + log.info(RECEIVED_MESSAGE, consumerRecord.topic(), consumerRecord.topic(), consumerRecord.key()); + } + } + return consumerRecords; + } + + @Override + public void onCommit(Map map) { + + } + + @Override + public ProducerRecord onSend(ProducerRecord producerRecord) { + final String keyAsString = ObjectUtils.nullSafeToString(producerRecord.key()); + + if (log.isDebugEnabled()) { + final String bodyAsJsonString = getMessageBodyAsJsonString(producerRecord.value()); + log.debug(SEND_SUCCESS_MESSAGE_WITH_BODY, producerRecord.topic(), producerRecord.partition(), bodyAsJsonString, + keyAsString); + } else { + log.info(SEND_SUCCESS_MESSAGE, producerRecord.topic(), producerRecord.partition(), keyAsString); + } + return producerRecord; + } + + @Override + public void onAcknowledgement(RecordMetadata recordMetadata, Exception e) { + if (!isNull(e)) { + final String message = + String.format(SEND_FAILURE_MESSAGE, recordMetadata.topic(), recordMetadata.partition()); + log.error(message, e); + } + } + + @Override + public void close() { + + } + + @Override + public void configure(Map map) { + + } + + private String getMessageBodyAsJsonString(Object value) { + try { + return objectMapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + log.warn(BODY_JSON_SERIALIZATION_ERROR); + return EMPTY_BODY; + } + } + + @SuppressWarnings("unchecked") + private String getCorrelationIdFromBody(Object value) { + String correlationId = null; + try { + Map requestMap = objectMapper.convertValue(value, Map.class); + + Object requestHeader = requestMap.containsKey(REQUEST_HEADER_FIELD_NAME_IN_JAVA_CLASS_CASE) ? requestMap.get + (REQUEST_HEADER_FIELD_NAME_IN_JAVA_CLASS_CASE) : requestMap.get(REQUEST_HEADER_IN_CAMEL_CASE); + + if (isNull(requestHeader)) + return null; + else { + if (requestHeader instanceof Map) { + correlationId = (String) ((Map) requestHeader).get(CORRELATION_ID_FIELD_NAME); + } + } + } catch (Exception ignored) { + } + + return correlationId; + } + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/LogAwareKafkaTemplate.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/LogAwareKafkaTemplate.java new file mode 100644 index 00000000..8a161f54 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/LogAwareKafkaTemplate.java @@ -0,0 +1,97 @@ +package org.egov.tracer.kafka; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.config.ObjectMapperFactory; +import org.egov.tracer.config.TracerProperties; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.SendResult; +import org.springframework.stereotype.Component; +import org.springframework.util.ObjectUtils; + +import java.util.concurrent.ExecutionException; + +@Slf4j +@Component +public class LogAwareKafkaTemplate { + + private static final String EMPTY_BODY = ""; + private static final String SEND_SUCCESS_MESSAGE = + "Sending of message to topic: {}, partition: {} with key: {} succeeded."; + private static final String BODY_JSON_SERIALIZATION_ERROR = "Serialization of body failed"; + private static final String SEND_SUCCESS_MESSAGE_WITH_BODY = + "Sending of message to topic: {}, partition: {}, body: {} with key: {} succeeded."; + private static final String SEND_FAILURE_MESSAGE_WITH_TOPIC = + "Sending of message to topic: %s failed."; + private static final String SEND_FAILURE_MESSAGE_WITH_TOPIC_KEY = + "Sending of message to topic: %s, key: %s failed."; + private static final String SEND_FAILURE_MESSAGE_WITH_TOPIC_KEY_PARTITION = + "Sending of message to topic: %s, partition: %s, key: %s failed."; + private TracerProperties tracerProperties; + private KafkaTemplate kafkaTemplate; + private ObjectMapper objectMapper; + + public LogAwareKafkaTemplate(TracerProperties tracerProperties, + KafkaTemplate kafkaTemplate, + ObjectMapperFactory objectMapperFactory) { + this.tracerProperties = tracerProperties; + this.kafkaTemplate = kafkaTemplate; + this.objectMapper = objectMapperFactory.getObjectMapper(); + } + + public SendResult send(String topic, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, value).get(); + logSuccessMessage(value, result); + return result; + } catch (InterruptedException | ExecutionException e) { + log.error(String.format(SEND_FAILURE_MESSAGE_WITH_TOPIC, topic), e); + throw new RuntimeException(e); + } + } + + public SendResult send(String topic, K key, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, key, value).get(); + logSuccessMessage(value, result); + return result; + } catch (InterruptedException | ExecutionException e) { + log.error(String.format(SEND_FAILURE_MESSAGE_WITH_TOPIC_KEY, topic, key), e); + throw new RuntimeException(e); + } + } + + public SendResult send(String topic, K key, int partition, V value) { + try { + final SendResult result = kafkaTemplate.send(topic, partition, key, value).get(); + logSuccessMessage(value, result); + return result; + } catch (InterruptedException | ExecutionException e) { + log.error(String.format(SEND_FAILURE_MESSAGE_WITH_TOPIC_KEY_PARTITION, topic, key, partition), e); + throw new RuntimeException(e); + } + } + + private void logSuccessMessage(V message, SendResult result) { + final String topic = result.getProducerRecord().topic(); + final Integer partition = result.getProducerRecord().partition(); + final String key = ObjectUtils.nullSafeToString(result.getProducerRecord().key()); + if (tracerProperties.isKafkaMessageLoggingEnabled()) { + final String bodyAsJsonString = getMessageBodyAsJsonString(message); + log.info(SEND_SUCCESS_MESSAGE_WITH_BODY, topic, partition, bodyAsJsonString, key); + } else { + log.info(SEND_SUCCESS_MESSAGE, topic, partition, key); + } + } + + private String getMessageBodyAsJsonString(Object value) { + try { + return objectMapper.writeValueAsString(value); + } catch (JsonProcessingException e) { + log.error(BODY_JSON_SERIALIZATION_ERROR); + return EMPTY_BODY; + } + } + +} \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/HashMapDeserializer.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/HashMapDeserializer.java new file mode 100644 index 00000000..7e736c4a --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/HashMapDeserializer.java @@ -0,0 +1,14 @@ +package org.egov.tracer.kafka.deserializer; + +import org.springframework.kafka.support.serializer.JsonDeserializer; + +import java.util.HashMap; + +public class HashMapDeserializer extends JsonDeserializer { + + public HashMapDeserializer() { + super(HashMap.class); + } + +} + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/ISTTimeZoneHashMapDeserializer.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/ISTTimeZoneHashMapDeserializer.java new file mode 100644 index 00000000..004c5ad3 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/deserializer/ISTTimeZoneHashMapDeserializer.java @@ -0,0 +1,23 @@ +package org.egov.tracer.kafka.deserializer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.kafka.support.serializer.JsonDeserializer; + +import java.util.HashMap; +import java.util.TimeZone; + +public class ISTTimeZoneHashMapDeserializer extends JsonDeserializer { + + private static final String IST = "Asia/Kolkata"; + + public ISTTimeZoneHashMapDeserializer() { + super(HashMap.class, getObjectMapper()); + } + + private static ObjectMapper getObjectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setTimeZone(TimeZone.getTimeZone(IST)); + return objectMapper; + } +} + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/serializer/ISTTimeZoneJsonSerializer.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/serializer/ISTTimeZoneJsonSerializer.java new file mode 100644 index 00000000..1dfccf05 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/kafka/serializer/ISTTimeZoneJsonSerializer.java @@ -0,0 +1,22 @@ +package org.egov.tracer.kafka.serializer; + +import com.fasterxml.jackson.databind.ObjectMapper; +import org.springframework.kafka.support.serializer.JsonSerializer; + +import java.util.HashMap; +import java.util.TimeZone; + +public class ISTTimeZoneJsonSerializer extends JsonSerializer { + + private static final String IST = "Asia/Kolkata"; + + public ISTTimeZoneJsonSerializer() { + super(getObjectMapper()); + } + + private static ObjectMapper getObjectMapper() { + final ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.setTimeZone(TimeZone.getTimeZone(IST)); + return objectMapper; + } +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomBindingResultExceprion.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomBindingResultExceprion.java new file mode 100644 index 00000000..f0eded94 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomBindingResultExceprion.java @@ -0,0 +1,18 @@ +package org.egov.tracer.model; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; +import org.springframework.validation.BindingResult; + +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +public class CustomBindingResultExceprion extends RuntimeException { + + private static final long serialVersionUID = 4581677752337709974L; + + private BindingResult bindingResult; +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomException.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomException.java new file mode 100644 index 00000000..b0184408 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/CustomException.java @@ -0,0 +1,35 @@ +package org.egov.tracer.model; + +import lombok.Getter; +import lombok.Setter; + +import java.util.Map; + +@Setter +@Getter +public class CustomException extends RuntimeException { + + private static final long serialVersionUID = 8859144435338793971L; + + private String code; + private String message; + private Map errors; + + public CustomException() { + super(); + } + + public CustomException(String code, String message) { + super(); + this.code = code; + this.message = message; + } + + public CustomException(Map errors) { + super(); + this.message = errors.toString(); + this.errors = errors; + } + + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/Error.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/Error.java new file mode 100644 index 00000000..6871ad62 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/Error.java @@ -0,0 +1,31 @@ +package org.egov.tracer.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.List; + +/** + * Error object will be returned as a part of reponse body in conjunction with + * responseHeader as part of ErrorResponse whenever the request processing status + * in the responseHeader is FAILED. + */ +@Setter +@Getter +@NoArgsConstructor +@AllArgsConstructor +@ToString +public class Error { + @JsonProperty("code") + private String code = null; + + @JsonProperty("message") + private String message = null; + + @JsonProperty("description") + private String description = null; + + @JsonProperty("params") + private List params = null; + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorQueueContract.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorQueueContract.java new file mode 100644 index 00000000..8f79e23b --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorQueueContract.java @@ -0,0 +1,26 @@ +package org.egov.tracer.model; + +import lombok.*; + +import java.util.List; + +@Setter +@Getter +@ToString +@NoArgsConstructor +@Builder +@AllArgsConstructor +public class ErrorQueueContract { + + private String id; + private String source; + private Object body; + private Long ts; + private ErrorRes errorRes; + private List exception; + //private String couse; + private String message; + //private Exception exception; + private String correlationId; + +} diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorRes.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorRes.java new file mode 100644 index 00000000..423b6ce0 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ErrorRes.java @@ -0,0 +1,27 @@ +package org.egov.tracer.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.apache.kafka.common.requests.ResponseHeader; + +import java.util.List; + + +/** + * All APIs will return ErrorRes in case of failure which will carry responseHeader as metadata and Error object as + * actual representation of error. In case of bulk apis, some apis may chose to return the array of Error objects to indicate individual failure. + */ +@Setter +@Getter +@ToString +public class ErrorRes { + + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("Errors") + private List errors = null; +} + diff --git a/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ServiceCallException.java b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ServiceCallException.java new file mode 100644 index 00000000..c5120c29 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/java/org/egov/tracer/model/ServiceCallException.java @@ -0,0 +1,16 @@ +package org.egov.tracer.model; + +import lombok.*; + +@Setter +@Getter +@ToString +@NoArgsConstructor +@AllArgsConstructor +public class ServiceCallException extends RuntimeException { + /** + * + */ + private static final long serialVersionUID = 1L; + private String error; +} diff --git a/core/libraries/ifix-tracer/src/main/resources/logback-spring-json.xml.bak b/core/libraries/ifix-tracer/src/main/resources/logback-spring-json.xml.bak new file mode 100644 index 00000000..a60f64f5 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/resources/logback-spring-json.xml.bak @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + { + "logger": "%logger{36}", + "message": "%message", + "level": "%level", + "thread": "%thread{10}" + } + + + + + + 30 + 2048 + 20 + ^sun\.reflect\..*\.invoke + ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke + true + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/main/resources/logback-spring.xml b/core/libraries/ifix-tracer/src/main/resources/logback-spring.xml new file mode 100644 index 00000000..dc708b6c --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/resources/logback-spring.xml @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + { + "logger": "%logger{30}", + "message": "%message", + "level": "%level", + "thread": "%thread{10}" + } + + + + + + 30 + 2048 + 20 + ^sun\.reflect\..*\.invoke + ^net\.sf\.cglib\.proxy\.MethodProxy\.invoke + true + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/main/resources/tracer.properties b/core/libraries/ifix-tracer/src/main/resources/tracer.properties new file mode 100644 index 00000000..d1cf2263 --- /dev/null +++ b/core/libraries/ifix-tracer/src/main/resources/tracer.properties @@ -0,0 +1,24 @@ +tracer.filter.enabled=true +tracer.opentracing.enabled=false +tracer.requestLoggingEnabled=false +tracer.kafkaMessageLoggingEnabled=false +tracer.restTemplateDetailedLoggingEnabled=false +tracer.errorsPublish=false +tracer.errorsTopic=egov-error +tracer.filterSkipPattern=/api-docs.*|/autoconfig|/configprops|/dump|/health|/info|/metrics\ + .*|/mappings|/swagger.*|.*\.png|.*\.css|.*\.js|.*\.html|/favicon.ico|/hystrix.stream|/prometheus|/manage/* +#Logging config +spring.kafka.properties.interceptor.classes=org.egov.tracer.kafka.KafkaTemplateLoggingInterceptors +# Actuator Configs +endpoints.enabled=false +endpoints.health.enabled=true +endpoints.prometheus.enabled=true +# Open Tracing / Jaeger Configs +opentracing.spring.web.skipPattern=/api-docs.*|/autoconfig|/configprops|/dump|/health|/info|/metrics\ + .*|/mappings|/swagger.*|.*\.png|.*\.css|.*\.js|.*\.html|/favicon.ico|/hystrix.stream|/prometheus|/manage/* +opentracing.spring.web.order=2 +opentracing.spring.cloud.jdbc.withActiveSpanOnly=true +opentracing.spring.cloud.jdbc.ignoreStatements=SELECT 1 +# Kafka Configs +spring.kafka.producer.acks=all +spring.kafka.producer.linger.ms=100 diff --git a/core/libraries/ifix-tracer/src/test/java/org/egov/ObjectMapperTest.java b/core/libraries/ifix-tracer/src/test/java/org/egov/ObjectMapperTest.java new file mode 100644 index 00000000..3e926bd6 --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/java/org/egov/ObjectMapperTest.java @@ -0,0 +1,58 @@ +package org.egov; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Getter; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +public class ObjectMapperTest { + + @Test + public void test_should_convert_class_instance_to_map() { + final Foo foo = new Foo("value1", new SubFoo("value2")); + final HashMap hashMap = new ObjectMapper().convertValue(foo, HashMap.class); + + assertNotNull(hashMap); + assertEquals("value1", hashMap.get("bar1")); + @SuppressWarnings("unchecked") final HashMap subFoo = + (HashMap) hashMap.get("subFoo"); + assertNotNull(subFoo); + assertEquals("value2", subFoo.get("bar2")); + } + + @Test + public void test_should_convert_map_to_map() { + final HashMap foo = new HashMap<>(); + foo.put("bar1", "value1"); + final HashMap subFoo = new HashMap<>(); + subFoo.put("bar2", "value2"); + foo.put("subFoo", subFoo); + final HashMap hashMap = new ObjectMapper().convertValue(foo, HashMap.class); + + assertNotNull(hashMap); + assertEquals("value1", hashMap.get("bar1")); + @SuppressWarnings("unchecked") final HashMap subFooMap = + (HashMap) hashMap.get("subFoo"); + assertNotNull(subFooMap); + assertEquals("value2", subFooMap.get("bar2")); + } + + @Getter + @AllArgsConstructor + private class Foo { + private String bar1; + private SubFoo subFoo; + } + + @Getter + @AllArgsConstructor + private class SubFoo { + private String bar2; + } +} + diff --git a/core/libraries/ifix-tracer/src/test/java/org/egov/Resources.java b/core/libraries/ifix-tracer/src/test/java/org/egov/Resources.java new file mode 100644 index 00000000..bf4c1f5a --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/java/org/egov/Resources.java @@ -0,0 +1,17 @@ +package org.egov; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; + +public class Resources { + public String getFileContents(String fileName) { + try { + return IOUtils.toString(this.getClass().getClassLoader() + .getResourceAsStream(fileName), "UTF-8") + .replace(" ", "").replace("\n", ""); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/libraries/ifix-tracer/src/test/java/org/egov/tracer/kafka/KafkaListenerLoggingAspectTest.java b/core/libraries/ifix-tracer/src/test/java/org/egov/tracer/kafka/KafkaListenerLoggingAspectTest.java new file mode 100644 index 00000000..4a58b43b --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/java/org/egov/tracer/kafka/KafkaListenerLoggingAspectTest.java @@ -0,0 +1,246 @@ +package org.egov.tracer.kafka; + +import org.egov.tracer.config.TracerConfiguration; +import org.egov.tracer.config.TracerProperties; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Rule; +import org.junit.Test; +import org.junit.contrib.java.lang.system.SystemOutRule; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.messaging.handler.annotation.Payload; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringRunner; + +import java.util.HashMap; + +import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +@RunWith(SpringRunner.class) +@ContextConfiguration(classes = {TracerConfiguration.class, TestConfiguration.class}) +public class KafkaListenerLoggingAspectTest { + + private static final String TEST_CORRELATION_ID = "testCorrelationId"; + @Rule + public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); + + @Autowired + private KafkaListenerWithOnlyPayloadAnnotatedHashMap kafkaListenerWithOnlyPayloadAnnotatedHashMap; + + @Autowired + private KafkaListenerStringPayloadWithTopicHeaderAnnotation kafkaListenerStringPayloadWithTopicHeaderAnnotation; + + @Autowired + private KafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation + kafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation; + + @Autowired + private KafkaListenerStringPayloadWithNonTopicHeaderAnnotation + kafkaListenerStringPayloadWithNonTopicHeaderAnnotation; + + @Autowired + private TracerProperties tracerProperties; + + @Before + public void before() { + systemOutRule.clearLog(); + } + + @Test + public void test_should_retrieve_correlation_id_from_hash_map_payload_and_set_to_context() { + final HashMap payload = new HashMap<>(); + final HashMap requestHeader = new HashMap<>(); + requestHeader.put("correlationId", TEST_CORRELATION_ID); + payload.put("requestHeader", requestHeader); + + kafkaListenerWithOnlyPayloadAnnotatedHashMap.bar(payload); + + } + + @Test + public void test_should_set_context_with_random_correlation_id_when_hash_map_payload_does_not_have_correlation_id_field() { + final HashMap payload = new HashMap<>(); + final HashMap requestHeader = new HashMap<>(); + requestHeader.put("foo", "abc"); + payload.put("requestHeader", requestHeader); + + kafkaListenerWithOnlyPayloadAnnotatedHashMap.bar(payload); + + } + + @Test + @Ignore + public void test_simple_log_message_should_mention_topic_name_is_unavailable_when_topic_header_annotation_is_not_present() { + final HashMap payload = new HashMap<>(); + final HashMap requestHeader = new HashMap<>(); + requestHeader.put("foo", "abc"); + payload.put("requestheader", requestHeader); + when(tracerProperties.isRequestLoggingEnabled()).thenReturn(false); + + kafkaListenerWithOnlyPayloadAnnotatedHashMap.bar(payload); + + assertTrue(systemOutRule.getLog().contains("Received message from topic: ")); + } + + @Test + @Ignore + public void test_detail_message_should_print_unavailable_topic_name_and_stringified_payload() { + final HashMap payload = new HashMap<>(); + final HashMap requestheader = new HashMap<>(); + requestheader.put("foo", "abc"); + payload.put("requestHeader", requestheader); + when(tracerProperties.isRequestLoggingEnabled()).thenReturn(true); + + kafkaListenerWithOnlyPayloadAnnotatedHashMap.bar(payload); + + final String expectedBody = "{\"requestHeader\":{\"foo\":\"abc\"}}"; + final String expectedMessage = "Received message from topic: with body " + expectedBody; + assertTrue(systemOutRule.getLog().contains(expectedMessage)); + } + + @Test + public void test_should_retrieve_correlation_id_from_string_payload_and_set_to_context() { + final String payload = "{\"requestHeader\": { \"correlationId\": \"testCorrelationId\"}}"; + + kafkaListenerStringPayloadWithTopicHeaderAnnotation.bar(payload, "actualTopic"); + + } + + @Test + public void test_should_set_random_correlation_id_to_context_when_string_payload_does_not_have_correlation_id_field() { + final String payload = "{\"requestHeader\": { \"foo\": \"bar\"}}"; + + kafkaListenerStringPayloadWithTopicHeaderAnnotation.bar(payload, "actualTopic"); + + } + + @Test + @Ignore + public void test_should_print_detailed_log_with_stringified_body_and_topic_name() { + final String payload = "{\"requestHeader\": { \"foo\": \"bar\"}}"; + when(tracerProperties.isRequestLoggingEnabled()).thenReturn(true); + kafkaListenerStringPayloadWithTopicHeaderAnnotation.bar(payload, "actualTopic"); + + final String expectedMessage = "Received message from topic: actualTopic with body " + payload; + assertTrue(systemOutRule.getLog().contains(expectedMessage)); + } + + @Test + @Ignore + public void test_should_set_random_correlation_id_when_payload_parameter_is_not_annotated() { + final HashMap payload = new HashMap<>(); + final HashMap requestHeader = new HashMap<>(); + requestHeader.put("foo", "abc"); + payload.put("requestHeader", requestHeader); + + kafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation.bar(payload); + + } + + @Test + @Ignore + public void test_should_print_detailed_log_with_unavailable_body_and_unavailable_topic_name() { + final HashMap payload = new HashMap<>(); + final HashMap requestHeader = new HashMap<>(); + requestHeader.put("foo", "abc"); + payload.put("requestHeader", requestHeader); + + kafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation.bar(payload); + + final String expectedMessage = "Received message from topic: with body "; + assertTrue(systemOutRule.getLog().contains(expectedMessage)); + } + + @Test + @Ignore + public void test_should_print_detailed_log_with_stringified_body_and_unavailable_topic_name() { + final String payload = "{\"requestHeader\": { \"foo\": \"bar\"}}"; + when(tracerProperties.isRequestLoggingEnabled()).thenReturn(true); + + kafkaListenerStringPayloadWithNonTopicHeaderAnnotation.bar(payload, 3); + + final String expectedMessage = "Received message from topic: with body " + payload; + assertTrue(systemOutRule.getLog().contains(expectedMessage)); + } + +} + +@Configuration +class TestConfiguration { + + @Bean + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } + + @Bean + public KafkaListenerWithOnlyPayloadAnnotatedHashMap kafkaListenerWithOnlyHashMapPayload() { + return new KafkaListenerWithOnlyPayloadAnnotatedHashMap(); + } + + @Bean + public KafkaListenerStringPayloadWithTopicHeaderAnnotation kafkaListenerStringPayloadWithAnnotation() { + return new KafkaListenerStringPayloadWithTopicHeaderAnnotation(); + } + + @Bean + public KafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation + kafkaListenerWithPayloadNotHavingPayloadAnnotation() { + return new KafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation(); + } + + @Bean + public KafkaListenerStringPayloadWithNonTopicHeaderAnnotation + kafkaListenerStringPayloadWithNonTopicHeaderAnnotation() { + return new KafkaListenerStringPayloadWithNonTopicHeaderAnnotation(); + } + + @Bean + public TracerProperties tracerProperties() { + final TracerProperties tracerProperties = mock(TracerProperties.class); + when(tracerProperties.isRequestLoggingEnabled()).thenReturn(true); + return tracerProperties; + } +} + +class KafkaListenerWithOnlyPayloadAnnotatedHashMap { + + @KafkaListener(topics = "${my.topics1}") + public void bar(@Payload HashMap payload) { + + } +} + +class KafkaListenerStringPayloadWithTopicHeaderAnnotation { + + @KafkaListener(topics = "${my.topics2}") + public void bar(@Payload String payload, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + + } +} + +class KafkaListenerWithoutPayloadAnnotationAndWithoutTopicHeaderAnnotation { + + @KafkaListener(topics = "${my.topics1}") + public void bar(HashMap payload) { + + } +} + +class KafkaListenerStringPayloadWithNonTopicHeaderAnnotation { + + @KafkaListener(topics = "${my.topics2}") + public void bar(@Payload String payload, @Header(KafkaHeaders.RECEIVED_PARTITION_ID) int partition) { + + } +} + diff --git a/core/libraries/ifix-tracer/src/test/resources/requestBodyWithCorrelationIdPresentInRequestInfo.json b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithCorrelationIdPresentInRequestInfo.json new file mode 100644 index 00000000..ad492100 --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithCorrelationIdPresentInRequestInfo.json @@ -0,0 +1,6 @@ +{ + "requestHeader": { + "correlationId": "someCorrelationId" + }, + "foo": "bar" +} \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutCorrelationIdPresentInRequestInfo.json b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutCorrelationIdPresentInRequestInfo.json new file mode 100644 index 00000000..5b910656 --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutCorrelationIdPresentInRequestInfo.json @@ -0,0 +1,6 @@ +{ + "requestHeader": { + "foo": "bar" + }, + "foo": "bar" +} \ No newline at end of file diff --git a/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutRequestInfoField.json b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutRequestInfoField.json new file mode 100644 index 00000000..b42f309e --- /dev/null +++ b/core/libraries/ifix-tracer/src/test/resources/requestBodyWithoutRequestInfoField.json @@ -0,0 +1,3 @@ +{ + "foo": "bar" +} \ No newline at end of file diff --git a/core/libraries/ifix-tracer/verify.sh b/core/libraries/ifix-tracer/verify.sh new file mode 100644 index 00000000..d9db414f --- /dev/null +++ b/core/libraries/ifix-tracer/verify.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env bash +./mvnw clean test verify From e262fde302b8fc6baf6483a36075335bb9f7040d Mon Sep 17 00:00:00 2001 From: GhanshyamRawat-eGov Date: Mon, 23 Aug 2021 19:44:29 +0530 Subject: [PATCH 06/67] Create .gitignore (#24) accepting only gitignore --- reference-adapter/.gitignore | 42 ++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 reference-adapter/.gitignore diff --git a/reference-adapter/.gitignore b/reference-adapter/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/reference-adapter/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache From ee3dabf6ee618bad4068a28d5af4c85c94d1fffe Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:20:06 +0530 Subject: [PATCH 07/67] Fiscal event post processor (#28) * Update build-config.yml (#3) * Update build-config.yml (#4) * Update build-config.yml (#5) * Updated Dockerfile base image (#6) * Fiscal Event Post Processor: Initial Commit * Update build-config.yml (#12) * IFIX:244 : Service, producer and other packages, classes * IFIX:244 : Service, producer and other packages, classes * Rahu ifix 244 (#15) * Push to MongoDB: config and instruction * Update README.md * Pk fiscal event post processor (#17) * Update README.md * Refactor consumer name * Flattening fiscal event data * Fix: Kafka consumer properties * Version change * Addition of ingestionTime and version change * Added instructions and config for Push to Druid. * Updated Druid config. Co-authored-by: rushang7-eGov Co-authored-by: Rushang Dhanesha Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Co-authored-by: rahu-eGov --- build/build-config.yml | 15 ++ .../fiscal-event-post-processor/.gitignore | 42 +++++ .../fiscal-event-post-processor/README.md | 28 ++++ .../druid-ingestion-config.json | 107 +++++++++++++ .../fiscal-event-mongodb-sink.json | 34 +++++ .../fiscal-event-post-processor/pom.xml | 103 +++++++++++++ .../src/main/java/org/egov/Main.java | 17 +++ .../FiscalEventPostProcessorConfig.java | 97 ++++++++++++ .../org/egov/config/MainConfiguration.java | 39 +++++ .../FiscalEventDereferenceConsumer.java | 46 ++++++ .../FiscalEventUnbundledFlattenConsumer.java | 59 +++++++ .../main/java/org/egov/producer/Producer.java | 18 +++ .../resposioty/ServiceRequestRepository.java | 48 ++++++ ...scalEventDereferenceEnrichmentService.java | 37 +++++ .../FiscalEventDereferenceService.java | 144 ++++++++++++++++++ .../service/FiscalEventFlattenService.java | 33 ++++ .../service/FiscalEventUnbundleService.java | 67 ++++++++ .../src/main/java/org/egov/util/CoaUtil.java | 90 +++++++++++ .../java/org/egov/util/DepartmentUtil.java | 64 ++++++++ .../java/org/egov/util/ExpenditureUtil.java | 69 +++++++++ .../java/org/egov/util/GovernmentUtil.java | 77 ++++++++++ .../org/egov/util/MasterDataConstants.java | 34 +++++ .../main/java/org/egov/util/ProjectUtil.java | 72 +++++++++ .../main/java/org/egov/web/models/Amount.java | 40 +++++ .../web/models/AmountDetailsDeReferenced.java | 40 +++++ .../org/egov/web/models/ChartOfAccount.java | 66 ++++++++ .../java/org/egov/web/models/Department.java | 32 ++++ .../java/org/egov/web/models/Expenditure.java | 67 ++++++++ .../java/org/egov/web/models/FiscalEvent.java | 107 +++++++++++++ .../web/models/FiscalEventDeReferenced.java | 82 ++++++++++ .../org/egov/web/models/FiscalEventDruid.java | 20 +++ .../models/FiscalEventLineItemUnbundled.java | 79 ++++++++++ .../egov/web/models/FiscalEventMongoDB.java | 20 +++ .../egov/web/models/FiscalEventRequest.java | 35 +++++ .../java/org/egov/web/models/Government.java | 27 ++++ .../java/org/egov/web/models/Project.java | 38 +++++ .../src/main/resources/application.properties | 53 +++++++ .../test/java/org/egov/TestConfiguration.java | 16 ++ 38 files changed, 2062 insertions(+) create mode 100644 domain-services/fiscal-event-post-processor/.gitignore create mode 100644 domain-services/fiscal-event-post-processor/README.md create mode 100644 domain-services/fiscal-event-post-processor/druid-ingestion-config.json create mode 100644 domain-services/fiscal-event-post-processor/fiscal-event-mongodb-sink.json create mode 100644 domain-services/fiscal-event-post-processor/pom.xml create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/Main.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/FiscalEventPostProcessorConfig.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/MainConfiguration.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/producer/Producer.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/resposioty/ServiceRequestRepository.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventFlattenService.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/CoaUtil.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/GovernmentUtil.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Amount.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/AmountDetailsDeReferenced.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/ChartOfAccount.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Department.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Expenditure.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Government.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/resources/application.properties create mode 100644 domain-services/fiscal-event-post-processor/src/test/java/org/egov/TestConfiguration.java diff --git a/build/build-config.yml b/build/build-config.yml index d6a96f35..a8dadd04 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -21,3 +21,18 @@ config: - work-dir: "domain-services/ifix-master-data-service" image-name: "ifix-master-data-service" dockerfile: "build/maven/Dockerfile" + - name: "builds/iFix/domain-services/fiscal-event-service" + build: + - work-dir: "domain-services/fiscal-event-service" + image-name: "fiscal-event-service" + dockerfile: "build/maven/Dockerfile" + - name: "builds/iFix/domain-services/fiscal-event-post-processor" + build: + - work-dir: "domain-services/fiscal-event-post-processor" + image-name: "fiscal-event-post-processor" + dockerfile: "build/maven/Dockerfile" + - name: "builds/iFix/core/ifix-zuul" + build: + - work-dir: "core/ifix-zuul" + image-name: "ifix-zuul" + dockerfile: "build/maven/Dockerfile" diff --git a/domain-services/fiscal-event-post-processor/.gitignore b/domain-services/fiscal-event-post-processor/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/domain-services/fiscal-event-post-processor/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/domain-services/fiscal-event-post-processor/README.md b/domain-services/fiscal-event-post-processor/README.md new file mode 100644 index 00000000..d52800f0 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/README.md @@ -0,0 +1,28 @@ +# Fiscal Event Post Processor + +We are going to store all the **fiscal-event** in 2 data stores: +1. MongoDB +2. Druid + +## Kafka to DataStore Sink + +### MongoDB Sink +We can use kafka-connect to push the data from a kafka topic to MongoDB. We will have to follow these steps to start the connector: +1. Connect(port-forward) with the kafka-connect server. +2. We can create a new connector with a POST API call to localhost:8083/connectors. +3. The request body for that API call is written in the file [fiscal-event-mongodb-sink](./fiscal-event-mongodb-sink.json). +4. Within that file, wherever ${---} replace it with the actual value based on the environment. Get ${mongo-db-authenticated-uri} from the configured secrets of the environment. +5. *(Optional)* Verify and make changes to the topic names. +6. The connector is ready. You can check it using API call GET localhost:8083/connectors. + +### Druid Sink +We will use the Druid console to start ingesting data from a kafka topic to the Druid data store. Please follow +the steps mentioned below to start the *Druid Supervisor*: +1. Open the Druid console +2. Go to the **Load Data** section +3. Select **Other** +4. Click on **Submit Supervisor** +5. Copy...Paste the JSON from the [druid-ingestion-config.json](./druid-ingestion-config.json) file in the available + text box. +6. You should verify the kafka topic name and the kafka bootstrap server address before submitting the config. +7. Now submit the config and the data ingestion should start into the **fiscal-event** _datasource_. diff --git a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json new file mode 100644 index 00000000..2832dbcc --- /dev/null +++ b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json @@ -0,0 +1,107 @@ +{ + "type": "kafka", + "spec": { + "ioConfig": { + "type": "kafka", + "consumerProperties": { + "bootstrap.servers": "kafka-v2.ifix:9092" + }, + "topic": "fiscal-event-druid-sink", + "inputFormat": { + "type": "json" + }, + "useEarliestOffset": true + }, + "tuningConfig": { + "type": "kafka" + }, + "dataSchema": { + "dataSource": "fiscal-event", + "timestampSpec": { + "column": "ingestionTime", + "format": "millis" + }, + "dimensionsSpec": { + "dimensions": [ + { + "type": "double", + "name": "amount" + }, + { + "type": "long", + "name": "coa.groupHead" + }, + "coa.groupHeadName", + "coa.id", + { + "type": "long", + "name": "coa.majorHead" + }, + "coa.majorHeadName", + { + "type": "long", + "name": "coa.minorHead" + }, + "coa.minorHeadName", + { + "type": "long", + "name": "coa.objectHead" + }, + "coa.objectHeadName", + { + "type": "long", + "name": "coa.subHead" + }, + "coa.subHeadName", + { + "type": "long", + "name": "coa.subMajorHead" + }, + "coa.subMajorHeadName", + "department.code", + "department.id", + "department.name", + "eventId", + { + "type": "long", + "name": "eventTime" + }, + "eventType", + { + "type": "long", + "name": "expenditure.code" + }, + "expenditure.id", + "expenditure.name", + "expenditure.type", + { + "type": "long", + "name": "fromBillingPeriod" + }, + "government.id", + "government.name", + "id", + "parentEventId", + "parentReferenceId", + "project.code", + "project.departmentId", + "project.expenditureId", + "project.id", + "project.name", + "referenceId", + "tenantId", + { + "type": "long", + "name": "toBillingPeriod" + }, + "version" + ] + }, + "granularitySpec": { + "queryGranularity": "none", + "rollup": false, + "segmentGranularity": "hour" + } + } + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-post-processor/fiscal-event-mongodb-sink.json b/domain-services/fiscal-event-post-processor/fiscal-event-mongodb-sink.json new file mode 100644 index 00000000..ac3dc465 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/fiscal-event-mongodb-sink.json @@ -0,0 +1,34 @@ +{ + "name": "fiscal-event-mongodb-sink", + "config": { + "connector.class": "com.mongodb.kafka.connect.MongoSinkConnector", + "connection.uri": "${mongo-db-authenticated-uri}", + + "database": "${mongo-db-name}", + "collection": "fiscal_event", + + "topics": "fiscal-event-mongodb-sink", + + "key.ignore": "true", + "schema.ignore": true, + "value.converter.schemas.enable": false, + "key.converter": "org.apache.kafka.connect.storage.StringConverter", + "value.converter": "org.apache.kafka.connect.json.JsonConverter", + + "mongo.errors.tolerance": "all", + "mongo.errors.log.enable": true, + "errors.log.enable": true, + "errors.deadletterqueue.context.headers.enable": true, + "errors.deadletterqueue.topic.name": "fiscal-event-mongodb-dead-letter", + + "batch.size": 500, + "max.buffered.records": 1000, + "flush.timeout.ms": 600000, + "retry.backoff.ms": 5000, + "read.timout.ms": 10000, + "linger.ms": 1000, + "max.in.flight.requests": 2, + + "tasks.max": 1 + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-post-processor/pom.xml b/domain-services/fiscal-event-post-processor/pom.xml new file mode 100644 index 00000000..c170e0b0 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/pom.xml @@ -0,0 +1,103 @@ + + 4.0.0 + org.egov + fiscal-event-post-processor + jar + fiscal-event-post-processor + 1.0.0 + + 1.8 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + + + + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + + + org.egov.services + ifix-services-common + 0.0.1-SNAPSHOT + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + + com.github.wnameless.json + json-flattener + 0.12.0 + + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/Main.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/Main.java new file mode 100644 index 00000000..fca48a16 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/Main.java @@ -0,0 +1,17 @@ +package org.egov; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = {"org.egov", "org.egov.web.controllers", "org.egov.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/FiscalEventPostProcessorConfig.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/FiscalEventPostProcessorConfig.java new file mode 100644 index 00000000..04278764 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/FiscalEventPostProcessorConfig.java @@ -0,0 +1,97 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +public class FiscalEventPostProcessorConfig { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } + + @Value("${fiscal.event.processor.kafka.mongodb.topic}") + private String fiscalEventMongoDbSink; + + @Value("${fiscal.event.kafka.dereferenced.topic}") + private String fiscalEventDereferenceTopic; + + @Value("${fiscal.event.kafka.flattened.topic}") + private String fiscalEventFlattenedTopic; + + @Value("${fiscal.event.processor.kafka.druid.topic}") + private String fiscalEventDruidTopic; + + @Value("${ifix.master.coa.host}") + private String ifixMasterCoaHost; + + @Value("${ifix.master.coa.context.path}") + private String ifixMasterCoaContextPath; + + @Value("${ifix.master.coa.search.path}") + private String ifixMasterCoaSearchPath; + + @Value("${ifix.master.government.host}") + private String ifixMasterGovernmentHost; + + @Value("${ifix.master.government.context.path}") + private String ifixMasterGovernmentContextPath; + + @Value("${ifix.master.government.search.path}") + private String ifixMasterGovernmentSearchPath; + + @Value("${ifix.master.project.host}") + private String ifixMasterProjectHost; + + @Value("${ifix.master.project.context.path}") + private String ifixMasterProjectContextPath; + + @Value("${ifix.master.project.search.path}") + private String ifixMasterProjectSearchPath; + + @Value("${ifix.master.expenditure.host}") + private String ifixMasterExpenditureHost; + + @Value("${ifix.master.expenditure.context.path}") + private String ifixMasterExpenditureContextPath; + + @Value("${ifix.master.expenditure.search.path}") + private String ifixMasterExpenditureSearchPath; + + @Value("${ifix.master.department.host}") + private String ifixMasterDepartmentHost; + + @Value("${ifix.master.department.context.path}") + private String ifixMasterDepartmentContextPath; + + @Value("${ifix.master.department.search.path}") + private String ifixMasterDepartmentSearchPath; +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/MainConfiguration.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/MainConfiguration.java new file mode 100644 index 00000000..e4d1cb86 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/config/MainConfiguration.java @@ -0,0 +1,39 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java new file mode 100644 index 00000000..b81ff40e --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java @@ -0,0 +1,46 @@ +package org.egov.consumer; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.producer.Producer; +import org.egov.service.FiscalEventDereferenceService; +import org.egov.web.models.FiscalEventDeReferenced; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.HashMap; + +@Slf4j +@Component +public class FiscalEventDereferenceConsumer { + + @Autowired + private FiscalEventDereferenceService dereferenceService; + + @Autowired + private FiscalEventPostProcessorConfig processorConfig; + + @Autowired + private Producer producer; + + @Autowired + private ObjectMapper mapper; + + @KafkaListener(topics = {"${fiscal.event.kafka.push.topic}"}) + public void listen(final HashMap record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + try { + FiscalEventRequest fiscalEventRequest = mapper.convertValue(record, FiscalEventRequest.class); + FiscalEventDeReferenced fiscalEventDeReferenced = dereferenceService.dereference(fiscalEventRequest); + producer.push(processorConfig.getFiscalEventMongoDbSink(), fiscalEventDeReferenced); + producer.push(processorConfig.getFiscalEventDereferenceTopic(), fiscalEventDeReferenced); + } catch (Exception e) { + log.error("Error occurred while processing the record from topic : " + topic, e); + } + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java new file mode 100644 index 00000000..36b2fc41 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java @@ -0,0 +1,59 @@ +package org.egov.consumer; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.producer.Producer; +import org.egov.service.FiscalEventFlattenService; +import org.egov.service.FiscalEventUnbundleService; +import org.egov.web.models.FiscalEventDeReferenced; +import org.egov.web.models.FiscalEventLineItemUnbundled; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.kafka.support.KafkaHeaders; +import org.springframework.messaging.handler.annotation.Header; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; + +@Slf4j +@Component +public class FiscalEventUnbundledFlattenConsumer { + + @Autowired + private FiscalEventUnbundleService unbundleService; + + @Autowired + private FiscalEventPostProcessorConfig processorConfig; + + @Autowired + private Producer producer; + + @Autowired + private ObjectMapper mapper; + + @Autowired + private FiscalEventFlattenService flattenService; + + @KafkaListener(topics = {"${fiscal.event.kafka.dereferenced.topic}"}) + public void listen(final HashMap record, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) { + mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); + try { + FiscalEventDeReferenced fiscalEventDeReferenced = mapper.convertValue(record, FiscalEventDeReferenced.class); + List fiscalEventLineItemUnbundledList = unbundleService.unbundle(fiscalEventDeReferenced); + + List flattenJsonDataList = flattenService.getFlattenData(fiscalEventLineItemUnbundledList); + + if (!flattenJsonDataList.isEmpty()) { + for (String flattenJsonData : flattenJsonDataList) { + producer.push(processorConfig.getFiscalEventDruidTopic(), mapper.readValue(flattenJsonData, JsonNode.class)); + } + } + } catch (Exception e) { + log.error("Error occurred while processing the record from topic : " + topic, e); + } + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/producer/Producer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/producer/Producer.java new file mode 100644 index 00000000..11893443 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/producer/Producer.java @@ -0,0 +1,18 @@ +package org.egov.producer; + +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/resposioty/ServiceRequestRepository.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/resposioty/ServiceRequestRepository.java new file mode 100644 index 00000000..3020018f --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/resposioty/ServiceRequestRepository.java @@ -0,0 +1,48 @@ +package org.egov.resposioty; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Component +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + /** + * @param uri + * @param request + * @return + */ + public Object fetchResult(String uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri, request, Map.class); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); + } + + return response; + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java new file mode 100644 index 00000000..3012af60 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java @@ -0,0 +1,37 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.MasterDataConstants; +import org.egov.web.models.FiscalEvent; +import org.egov.web.models.FiscalEventDeReferenced; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Service +@Slf4j +public class FiscalEventDereferenceEnrichmentService { + + + public void enrich(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { + RequestHeader requestHeader = fiscalEventRequest.getRequestHeader(); + FiscalEvent fiscalEvent = fiscalEventRequest.getFiscalEvent(); + + fiscalEventDeReferenced.setIngestionTime(fiscalEvent.getIngestionTime()); + fiscalEventDeReferenced.setEventTime(fiscalEvent.getEventTime()); + fiscalEventDeReferenced.setEventType(fiscalEvent.getEventType().name()); + fiscalEventDeReferenced.setParentReferenceId(fiscalEvent.getParentReferenceId()); + fiscalEventDeReferenced.setParentEventId(fiscalEvent.getParentEventId()); + fiscalEventDeReferenced.setReferenceId(fiscalEvent.getReferenceId()); + fiscalEventDeReferenced.setAttributes(fiscalEvent.getAttributes()); + fiscalEventDeReferenced.setVersion(MasterDataConstants.FISCAL_EVENT_VERSION); + + fiscalEventDeReferenced.setAuditDetails(fiscalEvent.getAuditDetails()); + fiscalEventDeReferenced.setId(fiscalEvent.getId()); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java new file mode 100644 index 00000000..79a22ae9 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java @@ -0,0 +1,144 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.producer.Producer; +import org.egov.util.*; +import org.egov.web.models.*; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class FiscalEventDereferenceService { + + @Autowired + private FiscalEventDereferenceEnrichmentService enricher; + + @Autowired + private CoaUtil coaUtil; + + @Autowired + private GovernmentUtil governmentUtil; + + @Autowired + private ProjectUtil projectUtil; + + @Autowired + private ExpenditureUtil expenditureUtil; + + @Autowired + private DepartmentUtil departmentUtil; + + public FiscalEventDeReferenced dereference(FiscalEventRequest fiscalEventRequest) { + FiscalEventDeReferenced fiscalEventDeReferenced = new FiscalEventDeReferenced(); + dereferenceTenantId(fiscalEventRequest,fiscalEventDeReferenced); + dereferenceCoaId(fiscalEventRequest,fiscalEventDeReferenced); + dereferenceProjectId(fiscalEventRequest, fiscalEventDeReferenced); + enricher.enrich(fiscalEventRequest,fiscalEventDeReferenced); + return fiscalEventDeReferenced; + } + + private void dereferenceTenantId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { + List governments = governmentUtil.getGovernmentFromGovernmentService(fiscalEventRequest); + if(!governments.isEmpty()){ + fiscalEventDeReferenced.setGovernment(governments.get(0)); + } + fiscalEventDeReferenced.setTenantId(fiscalEventRequest.getFiscalEvent().getTenantId()); + } + + private void dereferenceCoaId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { + //copy the amount details except chart of account in deReferenced amount + List amtDetailsDereferenced = new ArrayList<>(); + if(fiscalEventRequest.getFiscalEvent() != null + && fiscalEventRequest.getFiscalEvent().getAmountDetails()!=null + && !fiscalEventRequest.getFiscalEvent().getAmountDetails().isEmpty()){ + for(Amount amount : fiscalEventRequest.getFiscalEvent().getAmountDetails()){ + AmountDetailsDeReferenced amountDetailsDeReferenced = new AmountDetailsDeReferenced(); + amountDetailsDeReferenced.setAmount(amount.getAmount()); + amountDetailsDeReferenced.setFromBillingPeriod(amount.getFromBillingPeriod()); + amountDetailsDeReferenced.setToBillingPeriod(amount.getToBillingPeriod()); + amountDetailsDeReferenced.setId(amount.getId()); + ChartOfAccount coa = new ChartOfAccount(); + coa.setId(amount.getCoaId()); + //coaIds.add(amount.getCoaId()); + amountDetailsDeReferenced.setCoa(coa); + + amtDetailsDereferenced.add(amountDetailsDeReferenced); + } + } + + //Get the chart of account details + List chartOfAccounts = coaUtil.getCOAIdsFromCOAService(fiscalEventRequest.getRequestHeader(), + fiscalEventRequest.getFiscalEvent()); + //copy the amount details except chart of account in deReferenced amount + List updatedAmtDereferences = new ArrayList<>(); + if(!chartOfAccounts.isEmpty()){ + for(AmountDetailsDeReferenced amtDeReferenced : amtDetailsDereferenced){ + AmountDetailsDeReferenced newAmtDereference = new AmountDetailsDeReferenced(); + BeanUtils.copyProperties(amtDeReferenced,newAmtDereference); + + for(ChartOfAccount chartOfAccount : chartOfAccounts){ + if(chartOfAccount.getId().equals(amtDeReferenced.getCoa().getId())){ + newAmtDereference.setCoa(chartOfAccount); + break; + } + } + + updatedAmtDereferences.add(newAmtDereference); + } + } + + fiscalEventDeReferenced.setAmountDetails(updatedAmtDereferences); + } + + /** + * @param fiscalEventRequest + * @param fiscalEventDeReferenced + */ + private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { + if (isValidProjectIdParam(fiscalEventRequest) && fiscalEventDeReferenced != null) { + List projectList = projectUtil.getProjectReference(fiscalEventRequest); + + if (projectList != null && !projectList.isEmpty()) { + Project project = projectList.get(0); + fiscalEventDeReferenced.setProject(project); + + List expenditureList = expenditureUtil.getExpenditureReference(fiscalEventRequest.getFiscalEvent().getTenantId(), + project.getExpenditureId(), fiscalEventRequest.getRequestHeader()); + if (expenditureList != null && !expenditureList.isEmpty()) { + fiscalEventDeReferenced.setExpenditure(expenditureList.get(0)); + } + + List departmentList = departmentUtil + .getDepartmentReference(fiscalEventRequest.getFiscalEvent().getTenantId(), + project.getDepartmentId(), fiscalEventRequest.getRequestHeader()); + if (departmentList != null && !departmentList.isEmpty()) { + fiscalEventDeReferenced.setDepartment(departmentList.get(0)); + } + } + } + } + + /** + * @param fiscalEventRequest + * @return + */ + private boolean isValidProjectIdParam(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getFiscalEvent() != null + && fiscalEventRequest.getRequestHeader() != null + && !StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getProjectId()) + && !StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getTenantId()) + ) { + return true; + } + + return false; + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventFlattenService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventFlattenService.java new file mode 100644 index 00000000..7f06062c --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventFlattenService.java @@ -0,0 +1,33 @@ +package org.egov.service; + +import com.github.wnameless.json.flattener.JsonFlattener; +import com.google.gson.Gson; +import lombok.extern.slf4j.Slf4j; +import org.egov.web.models.FiscalEventLineItemUnbundled; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +@Service +@Slf4j +public class FiscalEventFlattenService { + + /** + * @param eventLineItemUnbundledList + * @return + */ + public List getFlattenData(List eventLineItemUnbundledList) { + if (eventLineItemUnbundledList != null && !eventLineItemUnbundledList.isEmpty()) { + List flattenDataList = new ArrayList<>(); + + for (FiscalEventLineItemUnbundled lineItemUnbundled : eventLineItemUnbundledList) { + flattenDataList.add(JsonFlattener.flatten(new Gson().toJson(lineItemUnbundled))); + } + return flattenDataList; + } + + return Collections.emptyList(); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java new file mode 100644 index 00000000..77c877e5 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java @@ -0,0 +1,67 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.web.models.AmountDetailsDeReferenced; +import org.egov.web.models.FiscalEventDeReferenced; +import org.egov.web.models.FiscalEventLineItemUnbundled; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class FiscalEventUnbundleService { + + /** + * Unbundled the dereference fiscal event + * @param fiscalEventDeReferenced + * @return + */ + public List unbundle(FiscalEventDeReferenced fiscalEventDeReferenced) { + List fiscalEventLineItemUnbundledList = new ArrayList<>(); + List amountDetails = fiscalEventDeReferenced.getAmountDetails(); + if(amountDetails != null && !amountDetails.isEmpty()){ + for(AmountDetailsDeReferenced amountDetailsDeReferenced : amountDetails){ + fiscalEventLineItemUnbundledList.add(getUnbundleFiscalEventFromDereferenceEvent( + amountDetailsDeReferenced,fiscalEventDeReferenced)); + } + } + + return fiscalEventLineItemUnbundledList; + } + + /** + * + * @param amountDetailsDeReferenced + * @param fiscalEventDeReferenced + * @return + */ + private FiscalEventLineItemUnbundled getUnbundleFiscalEventFromDereferenceEvent(AmountDetailsDeReferenced amountDetailsDeReferenced, + FiscalEventDeReferenced fiscalEventDeReferenced) { + FiscalEventLineItemUnbundled fiscalEventLineItemUnbundled = new FiscalEventLineItemUnbundled(); + + fiscalEventLineItemUnbundled.setId(amountDetailsDeReferenced.getId()); + fiscalEventLineItemUnbundled.setEventId(fiscalEventDeReferenced.getId()); + + fiscalEventLineItemUnbundled.setAmount(amountDetailsDeReferenced.getAmount()); + fiscalEventLineItemUnbundled.setCoa(amountDetailsDeReferenced.getCoa()); + fiscalEventLineItemUnbundled.setFromBillingPeriod(amountDetailsDeReferenced.getFromBillingPeriod()); + fiscalEventLineItemUnbundled.setToBillingPeriod(amountDetailsDeReferenced.getToBillingPeriod()); + + fiscalEventLineItemUnbundled.setDepartment(fiscalEventDeReferenced.getDepartment()); + fiscalEventLineItemUnbundled.setIngestionTime(fiscalEventDeReferenced.getIngestionTime()); + fiscalEventLineItemUnbundled.setEventTime(fiscalEventDeReferenced.getEventTime()); + fiscalEventLineItemUnbundled.setEventType(fiscalEventDeReferenced.getEventType()); + fiscalEventLineItemUnbundled.setExpenditure(fiscalEventDeReferenced.getExpenditure()); + fiscalEventLineItemUnbundled.setGovernment(fiscalEventDeReferenced.getGovernment()); + fiscalEventLineItemUnbundled.setParentEventId(fiscalEventDeReferenced.getParentEventId()); + fiscalEventLineItemUnbundled.setParentReferenceId(fiscalEventDeReferenced.getParentReferenceId()); + fiscalEventLineItemUnbundled.setProject(fiscalEventDeReferenced.getProject()); + fiscalEventLineItemUnbundled.setReferenceId(fiscalEventDeReferenced.getReferenceId()); + fiscalEventLineItemUnbundled.setTenantId(fiscalEventDeReferenced.getTenantId()); + fiscalEventLineItemUnbundled.setVersion(fiscalEventDeReferenced.getVersion()); + return fiscalEventLineItemUnbundled; + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/CoaUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/CoaUtil.java new file mode 100644 index 00000000..37ae86cc --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/CoaUtil.java @@ -0,0 +1,90 @@ +package org.egov.util; + + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.resposioty.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.Amount; +import org.egov.web.models.ChartOfAccount; +import org.egov.web.models.FiscalEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +@Slf4j +public class CoaUtil { + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private FiscalEventPostProcessorConfig configuration; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + /** + * Get the COA Details from master data service + * + * @param requestHeader + * @param fiscalEvent + * @return + */ + public List getCOAIdsFromCOAService(RequestHeader requestHeader, FiscalEvent fiscalEvent) { + String url = createCoaSearchUrl(); + Map coaSearchRequest = createSearchCoaRequest(requestHeader, fiscalEvent); + + Object response = serviceRequestRepository.fetchResult(url, coaSearchRequest); + List chartOfAccounts = null; + try { + chartOfAccounts = JsonPath.read(response, MasterDataConstants.COA_JSON_PATH); + if (chartOfAccounts != null) { + return objectMapper.convertValue(chartOfAccounts, new TypeReference>() { + }); + } + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse coa response for coaIds"); + } + return Collections.emptyList(); + } + + private Map createSearchCoaRequest(RequestHeader requestHeader, FiscalEvent fiscalEvent) { + if (fiscalEvent != null && StringUtils.isNotBlank(fiscalEvent.getTenantId())) { + + List coaIds = new ArrayList<>(); + if (fiscalEvent.getAmountDetails() != null + && !fiscalEvent.getAmountDetails().isEmpty()) { + for (Amount amount : fiscalEvent.getAmountDetails()) { + if (StringUtils.isNotBlank(amount.getCoaId())) { + coaIds.add(amount.getCoaId()); + } + } + } + + Map coaSearchRequest = new HashMap<>(); + Map criteria = new HashMap<>(); + criteria.put(MasterDataConstants.IDS, coaIds); + criteria.put(MasterDataConstants.CRITERIA_TENANT_ID, fiscalEvent.getTenantId()); + + coaSearchRequest.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + coaSearchRequest.put(MasterDataConstants.CRITERIA, criteria); + return coaSearchRequest; + } + + return Collections.emptyMap(); + } + + private String createCoaSearchUrl() { + StringBuilder uriBuilder = new StringBuilder(configuration.getIfixMasterCoaHost()) + .append(configuration.getIfixMasterCoaContextPath()).append(configuration.getIfixMasterCoaSearchPath()); + return uriBuilder.toString(); + } + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java new file mode 100644 index 00000000..f700a5f8 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java @@ -0,0 +1,64 @@ +package org.egov.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.resposioty.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.Department; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class DepartmentUtil { + + @Autowired + FiscalEventPostProcessorConfig processorConfig; + + @Autowired + ServiceRequestRepository serviceRequestRepository; + + @Autowired + ObjectMapper objectMapper; + + public List getDepartmentReference(String tenantId, String departmentId, RequestHeader requestHeader) { + if (!StringUtils.isEmpty(tenantId) && !StringUtils.isEmpty(departmentId)) { + Map departmentValueMap = new HashMap<>(); + departmentValueMap.put(MasterDataConstants.IDS, Collections.singletonList(departmentId)); + departmentValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, tenantId); + + Map departmentMap = new HashMap<>(); + departmentMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + departmentMap.put(MasterDataConstants.CRITERIA, departmentValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchDepartmentUrl(), departmentMap); + + try{ + List departmentList = JsonPath.read(response, MasterDataConstants.DEPARTMENT_JSON_PATH); + + return objectMapper.convertValue(departmentList, new TypeReference>() {}); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + } + } + return Collections.emptyList(); + } + + private String createSearchDepartmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(processorConfig.getIfixMasterDepartmentHost()) + .append(processorConfig.getIfixMasterDepartmentContextPath()) + .append(processorConfig.getIfixMasterDepartmentSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java new file mode 100644 index 00000000..0774489c --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java @@ -0,0 +1,69 @@ +package org.egov.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.resposioty.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.Expenditure; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class ExpenditureUtil { + @Autowired + FiscalEventPostProcessorConfig processorConfig; + + @Autowired + ServiceRequestRepository serviceRequestRepository; + + @Autowired + ObjectMapper objectMapper; + + /** + * @param tenantId + * @param expenditureId + * @param requestHeader + * @return + */ + public List getExpenditureReference(String tenantId, String expenditureId, RequestHeader requestHeader) { + if (!StringUtils.isEmpty(tenantId) && !StringUtils.isEmpty(expenditureId)) { + Map expenditureValueMap = new HashMap<>(); + expenditureValueMap.put(MasterDataConstants.IDS, Collections.singletonList(expenditureId)); + expenditureValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, tenantId); + + Map expenditureMap = new HashMap<>(); + expenditureMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + expenditureMap.put(MasterDataConstants.CRITERIA, expenditureValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchExpenditureUrl(), expenditureMap); + + try{ + List expenditureList = JsonPath.read(response, MasterDataConstants.EXPENDITURE_JSON_PATH); + + return objectMapper.convertValue(expenditureList, new TypeReference>() {}); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + } + } + return Collections.emptyList(); + } + + private String createSearchExpenditureUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(processorConfig.getIfixMasterExpenditureHost()) + .append(processorConfig.getIfixMasterExpenditureContextPath()) + .append(processorConfig.getIfixMasterExpenditureSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/GovernmentUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/GovernmentUtil.java new file mode 100644 index 00000000..ccc4ad5f --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/GovernmentUtil.java @@ -0,0 +1,77 @@ +package org.egov.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.resposioty.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.FiscalEventRequest; +import org.egov.web.models.Government; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class GovernmentUtil { + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private FiscalEventPostProcessorConfig configuration; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + /** + * @param fiscalEventRequest + * @return + */ + public List getGovernmentFromGovernmentService(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null + && fiscalEventRequest.getFiscalEvent() != null + && StringUtils.isNotBlank(fiscalEventRequest.getFiscalEvent().getTenantId())) { + + Map tenantValueMap = new HashMap<>(); + tenantValueMap.put(MasterDataConstants.IDS, + Collections.singletonList(fiscalEventRequest.getFiscalEvent().getTenantId())); + + Map tenantMap = new HashMap<>(); + tenantMap.put(MasterDataConstants.REQUEST_HEADER, fiscalEventRequest.getRequestHeader()); + tenantMap.put(MasterDataConstants.CRITERIA, tenantValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchGovernmentUrl(), tenantMap); + List governments = null; + try { + governments = JsonPath.read(response, MasterDataConstants.TENANT_LIST); + if (governments != null && !governments.isEmpty()) { + return objectMapper.convertValue(governments, new TypeReference>() { + }); + } + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse government response for tenantId"); + } + } + return Collections.emptyList(); + } + + + /** + * @return + */ + private String createSearchGovernmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getIfixMasterGovernmentHost()) + .append(configuration.getIfixMasterGovernmentContextPath()) + .append(configuration.getIfixMasterGovernmentSearchPath()); + return uriBuilder.toString(); + } + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java new file mode 100644 index 00000000..4f3f394f --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java @@ -0,0 +1,34 @@ +package org.egov.util; + +public class MasterDataConstants { + public static final String PROJECT_ID = "PROJECT_ID"; + public static final String JSONPATH_ERROR = "JSONPATH_ERROR"; + public static final String FISCAL_EVENT = "FISCAL_EVENT"; + public static final String REFERENCE_ID = "REFERENCE_ID"; + public static final String EVENT_TYPE = "EVENT_TYPE"; + public static final String FISCAL_EVENT_VERSION = "0.0.2"; + + private MasterDataConstants() { + } + + public static final String IDS = "Ids"; + public static final String CRITERIA = "criteria"; + + public static final String GOVERNMENT_ID = "GOVERNMENT_ID"; + public static final String TENANT_ID = "TENANT_ID"; + public static final String EXPENDITURE_ID = "EXPENDITURE_ID"; + public static final String DEPARTMENT_ID = "DEPARTMENT_ID"; + public static final String LOCATION_ID = "LOCATION_ID"; + public static final String REQUEST_HEADER = "requestHeader"; + + public static final String CRITERIA_TENANT_ID = "tenantId"; + + public static final String TENANT_LIST = "$.government.*"; + public static final String PROJECT_LIST = "$.project.*"; + public static final String COA_IDS_JSON_PATH = "$.chartOfAccounts.*.id"; + public static final String EXPENDITURE_JSON_PATH = "$.expenditure.*"; + public static final String DEPARTMENT_JSON_PATH = "$.department.*"; + public static final String COA_JSON_PATH = "$.chartOfAccounts.*"; + + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java new file mode 100644 index 00000000..373159dd --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java @@ -0,0 +1,72 @@ +package org.egov.util; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.config.FiscalEventPostProcessorConfig; +import org.egov.resposioty.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.FiscalEventRequest; +import org.egov.web.models.Project; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class ProjectUtil { + @Autowired + FiscalEventPostProcessorConfig processorConfig; + + @Autowired + ServiceRequestRepository serviceRequestRepository; + + @Autowired + ObjectMapper objectMapper; + + /** + * @param fiscalEventRequest + * @return + */ + public List getProjectReference(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null + && fiscalEventRequest.getFiscalEvent() != null + && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getProjectId())) { + + Map projectValueMap = new HashMap<>(); + projectValueMap.put(MasterDataConstants.IDS, + Collections.singletonList(fiscalEventRequest.getFiscalEvent().getProjectId())); + projectValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, + fiscalEventRequest.getFiscalEvent().getTenantId()); + + Map ProjectMap = new HashMap<>(); + ProjectMap.put(MasterDataConstants.REQUEST_HEADER, fiscalEventRequest.getRequestHeader()); + ProjectMap.put(MasterDataConstants.CRITERIA, projectValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchProjectUrl(), ProjectMap); + + try{ + List projectList = JsonPath.read(response, MasterDataConstants.PROJECT_LIST); + + return objectMapper.convertValue(projectList, new TypeReference>() {}); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + } + } + return Collections.emptyList(); + } + + private String createSearchProjectUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(processorConfig.getIfixMasterProjectHost()) + .append(processorConfig.getIfixMasterProjectContextPath()) + .append(processorConfig.getIfixMasterProjectSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Amount.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Amount.java new file mode 100644 index 00000000..d11519eb --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Amount.java @@ -0,0 +1,40 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * Capture the transaction amount and chart of account corresponding to the transaction amount + */ +@ApiModel(description = "Capture the transaction amount and chart of account corresponding to the transaction amount") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Amount { + @JsonProperty("id") + private String id = null; + + @JsonProperty("amount") + private BigDecimal amount = null; + + @JsonProperty("coaId") + private String coaId = null; + + @JsonProperty("fromBillingPeriod") + private Long fromBillingPeriod = null; + + @JsonProperty("toBillingPeriod") + private Long toBillingPeriod = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/AmountDetailsDeReferenced.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/AmountDetailsDeReferenced.java new file mode 100644 index 00000000..e93b929c --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/AmountDetailsDeReferenced.java @@ -0,0 +1,40 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * Capture the transaction amount and chart of account corresponding to the transaction amount + */ +@ApiModel(description = "Capture the transaction amount and chart of account corresponding to the transaction amount") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AmountDetailsDeReferenced { + @JsonProperty("id") + private String id = null; + + @JsonProperty("amount") + private BigDecimal amount = null; + + @JsonProperty("coa") + private ChartOfAccount coa = null; + + @JsonProperty("fromBillingPeriod") + private Long fromBillingPeriod = null; + + @JsonProperty("toBillingPeriod") + private Long toBillingPeriod = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/ChartOfAccount.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/ChartOfAccount.java new file mode 100644 index 00000000..b3420952 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/ChartOfAccount.java @@ -0,0 +1,66 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * ChartOfAccount + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class ChartOfAccount { + @JsonProperty("id") + private String id = null; + + @JsonProperty("coaCode") + private String coaCode = null; + + @JsonProperty("majorHead") + private String majorHead = null; + + @JsonProperty("majorHeadName") + private String majorHeadName = null; + + @JsonProperty("majorHeadType") + private String majorHeadType = null; + + @JsonProperty("subMajorHead") + private String subMajorHead = null; + + @JsonProperty("subMajorHeadName") + private String subMajorHeadName = null; + + @JsonProperty("minorHead") + private String minorHead = null; + + @JsonProperty("minorHeadName") + private String minorHeadName = null; + + @JsonProperty("subHead") + private String subHead = null; + + @JsonProperty("subHeadName") + private String subHeadName = null; + + @JsonProperty("groupHead") + private String groupHead = null; + + @JsonProperty("groupHeadName") + private String groupHeadName = null; + + @JsonProperty("objectHead") + private String objectHead = null; + + @JsonProperty("objectHeadName") + private String objectHeadName = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Department.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Department.java new file mode 100644 index 00000000..9629be11 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Department.java @@ -0,0 +1,32 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * Department details + */ +@ApiModel(description = "Department details") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Department { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Expenditure.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Expenditure.java new file mode 100644 index 00000000..6c7318cc --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Expenditure.java @@ -0,0 +1,67 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * Expenditure details + */ +@ApiModel(description = "Expenditure details") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Expenditure { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + @JsonProperty("type") + private TypeEnum type = null; + + /** + * Type of the Expenditure + */ + public enum TypeEnum { + SCHEME("Scheme"), + + NON_SCHEME("Non-Scheme"); + + private String value; + + TypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static TypeEnum fromValue(String text) { + for (TypeEnum b : TypeEnum.values()) { + if (String.valueOf(b.value).equals(text)) { + return b; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java new file mode 100644 index 00000000..7fa2395d --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java @@ -0,0 +1,107 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonFormat; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * This object captures the fiscal information of external systems. + */ +@ApiModel(description = "This object captures the fiscal information of external systems.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEvent { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("projectId") + private String projectId = null; + + @JsonProperty("eventType") + private EventTypeEnum eventType = null; + + @JsonProperty("ingestionTime") + private Long ingestionTime = null; + + @JsonProperty("eventTime") + private Long eventTime = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("parentEventId") + private String parentEventId = null; + + @JsonProperty("parentReferenceId") + private String parentReferenceId = null; + + @JsonProperty("amountDetails") + @Valid + private List amountDetails = new ArrayList<>(); + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("attributes") + private Object attributes = null; + + + public enum EventTypeEnum { + Sanction("Sanction"), + Appropriation("Appropriation"), + Allocation("Allocation"), + IntraTransfer("IntraTransfer"), + InterTransfer("InterTransfer"), + Demand("Demand"), + Receipt("Receipt"), + Bill("Bill"), + Payment("Payment"); + + private String value; + + EventTypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static EventTypeEnum fromValue(String text) { + for (EventTypeEnum eventTypeEnum : EventTypeEnum.values()) { + if (String.valueOf(eventTypeEnum.value).equals(text)) { + return eventTypeEnum; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + + public FiscalEvent addAmountDetailsItem(Amount amountDetailsItem) { + this.amountDetails.add(amountDetailsItem); + return this; + } +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java new file mode 100644 index 00000000..d1e1d822 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java @@ -0,0 +1,82 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * It gets the whole master data objects based on the reference ids present in the incoming request + */ +@ApiModel(description = "It gets the whole master data objects based on the reference ids present in the incoming request") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventDeReferenced { + + @JsonProperty("version") + private String version = null; + + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("government") + private Government government = null; + + @JsonProperty("department") + private Department department = null; + + @JsonProperty("expenditure") + private Expenditure expenditure = null; + + @JsonProperty("project") + private Project project = null; + + @JsonProperty("eventType") + private String eventType = null; + + @JsonProperty("ingestionTime") + private Long ingestionTime = null; + + @JsonProperty("eventTime") + private Long eventTime = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("parentEventId") + private String parentEventId = null; + + @JsonProperty("parentReferenceId") + private String parentReferenceId = null; + + @JsonProperty("amountDetails") + @Valid + private List amountDetails = new ArrayList<>(); + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("attributes") + private Object attributes = null; + + public FiscalEventDeReferenced addAmountDetailsItem(AmountDetailsDeReferenced amountDetailsItem) { + this.amountDetails.add(amountDetailsItem); + return this; + } + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java new file mode 100644 index 00000000..aa1f5e31 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java @@ -0,0 +1,20 @@ +package org.egov.web.models; + +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * FiscalEventDruid + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +//@NoArgsConstructor +@Builder +public class FiscalEventDruid { + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java new file mode 100644 index 00000000..6660e9d6 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java @@ -0,0 +1,79 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * This is the unbundled line item into individual record from a given fiscal event. + */ +@ApiModel(description = "This is the unbundled line item into individual record from a given fiscal event.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventLineItemUnbundled { + + @JsonProperty("version") + private String version = null; + + @JsonProperty("id") + private String id = null; + + @JsonProperty("eventId") + private String eventId = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("government") + private Government government = null; + + @JsonProperty("department") + private Department department = null; + + @JsonProperty("expenditure") + private Expenditure expenditure = null; + + @JsonProperty("project") + private Project project = null; + + @JsonProperty("eventType") + private String eventType = null; + + @JsonProperty("ingestionTime") + private Long ingestionTime = null; + + @JsonProperty("eventTime") + private Long eventTime = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("parentEventId") + private String parentEventId = null; + + @JsonProperty("parentReferenceId") + private String parentReferenceId = null; + + @JsonProperty("amount") + private BigDecimal amount = null; + + @JsonProperty("coa") + private ChartOfAccount coa = null; + + @JsonProperty("fromBillingPeriod") + private Long fromBillingPeriod = null; + + @JsonProperty("toBillingPeriod") + private Long toBillingPeriod = null; + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java new file mode 100644 index 00000000..8b527c89 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java @@ -0,0 +1,20 @@ +package org.egov.web.models; + +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * FiscalEventMongoDB + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +//@NoArgsConstructor +@Builder +public class FiscalEventMongoDB { + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java new file mode 100644 index 00000000..4e32a430 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java @@ -0,0 +1,35 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * This object captures the fiscal information of external systems. + */ +@ApiModel(description = "This object captures the fiscal information of external systems.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventRequest { + + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("fiscalEvent") + private FiscalEvent fiscalEvent = null; + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Government.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Government.java new file mode 100644 index 00000000..6f7acf95 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Government.java @@ -0,0 +1,27 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * Government + */ +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Government { + @JsonProperty("id") + private String id = null; + + @JsonProperty("name") + private String name = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java new file mode 100644 index 00000000..1e558842 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java @@ -0,0 +1,38 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +/** + * Captures the Project attributes + */ +@ApiModel(description = "Captures the Project attributes") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:56:59.067+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Project { + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("expenditureId") + private String expenditureId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + +} + diff --git a/domain-services/fiscal-event-post-processor/src/main/resources/application.properties b/domain-services/fiscal-event-post-processor/src/main/resources/application.properties new file mode 100644 index 00000000..95afbc0e --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/resources/application.properties @@ -0,0 +1,53 @@ +spring.main.web-application-type=NONE +app.timezone=UTC + +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=localhost:9092 +spring.kafka.consumer.value-deserializer=org.egov.tracer.kafka.deserializer.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=fiscal-event-post-processor +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA CONSUMER CONFIGURATIONS +kafka.consumer.config.auto_commit=true +kafka.consumer.config.auto_commit_interval=100 +kafka.consumer.config.session_timeout=15000 +kafka.consumer.config.auto_offset_reset=earliest +spring.kafka.listener.missing-topics-fatal=false +spring.kafka.consumer.properties.spring.json.use.type.headers=false + +# KAFKA PRODUCER CONFIGURATIONS +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 +#org.egov.detailed.tracing.enabled = false + +## Topic configuration ## +fiscal.event.kafka.push.topic=fiscal-event-request-validated +fiscal.event.kafka.dereferenced.topic=fiscal-event-request-dereferenced +fiscal.event.kafka.flattened.topic=fiscal-event-line-item-flattened +fiscal.event.processor.kafka.mongodb.topic=fiscal-event-mongodb-sink +fiscal.event.processor.kafka.druid.topic=fiscal-event-druid-sink + +## Uri Configurations ## +ifix.master.coa.host=http://localhost:8030 +ifix.master.coa.context.path=/ifix-master-data +ifix.master.coa.search.path=/chartOfAccount/v1/_search + +ifix.master.government.host=http://localhost:8030 +ifix.master.government.context.path=/ifix-master-data +ifix.master.government.search.path=/government/v1/_search + +ifix.master.project.host=http://localhost:8030 +ifix.master.project.context.path=/ifix-master-data +ifix.master.project.search.path=/project/v1/_search + +ifix.master.expenditure.host=http://localhost:8030 +ifix.master.expenditure.context.path=/ifix-master-data +ifix.master.expenditure.search.path=/expenditure/v1/_search + +ifix.master.department.host=http://localhost:8030 +ifix.master.department.context.path=/ifix-master-data +ifix.master.department.search.path=/department/v1/_search diff --git a/domain-services/fiscal-event-post-processor/src/test/java/org/egov/TestConfiguration.java b/domain-services/fiscal-event-post-processor/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file From 7d15f8c7c95f60b7645b7452d3ae751bd15935e4 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:20:52 +0530 Subject: [PATCH 08/67] Fiscal event service (#29) * Update build-config.yml (#3) * Update build-config.yml (#4) * Update build-config.yml (#5) * Updated Dockerfile base image (#6) * Fiscal Event Service: Initial commit * Pk fiscal event service (#11) * IFIX-230 : Added the producer and other package * IFIX-230 : Basic validator, enricher and other packages structure Co-authored-by: pintu-eGov * IFIX-230 : Moved service package * Update build-config.yml (#12) * Rahu ifix 230 (#14) * IFIX-230 : Validate the COA Ids from master service , Enriched the details * validate tenant and project Id * Naming convention resolved Co-authored-by: pintu-eGov * Coa Uri config * Coa Uri config * modified the coa - error message * EventTypeEnum key value correction * addition of ingestionTime * Migration scripts for fiscal event Co-authored-by: rushang7-eGov Co-authored-by: Rushang Dhanesha Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Co-authored-by: rahu-eGov --- .../fiscal-event-service/.gitignore | 42 +++++ .../fiscal-event-service/README.md | 1 + domain-services/fiscal-event-service/pom.xml | 95 +++++++++++ .../src/main/java/org/egov/Main.java | 17 ++ .../egov/config/FiscalEventConfiguration.java | 58 +++++++ .../org/egov/config/MainConfiguration.java | 39 +++++ .../main/java/org/egov/producer/Producer.java | 20 +++ .../repository/FiscalEventRepository.java | 10 ++ .../repository/ServiceRequestRepository.java | 49 ++++++ .../service/FiscalEventEnrichmentService.java | 54 +++++++ .../org/egov/service/FiscalEventService.java | 40 +++++ .../src/main/java/org/egov/util/CoaUtil.java | 76 +++++++++ .../java/org/egov/util/FiscalEventUtil.java | 32 ++++ .../org/egov/util/MasterDataConstants.java | 30 ++++ .../main/java/org/egov/util/ProjectUtil.java | 64 ++++++++ .../org/egov/util/ResponseHeaderCreator.java | 26 +++ .../main/java/org/egov/util/TenantUtil.java | 68 ++++++++ .../egov/validator/FiscalEventValidator.java | 149 ++++++++++++++++++ .../web/controllers/FiscalApiController.java | 60 +++++++ .../main/java/org/egov/web/models/Amount.java | 40 +++++ .../java/org/egov/web/models/Criteria.java | 63 ++++++++ .../java/org/egov/web/models/FiscalEvent.java | 107 +++++++++++++ .../web/models/FiscalEventGetRequest.java | 30 ++++ .../egov/web/models/FiscalEventRequest.java | 31 ++++ .../egov/web/models/FiscalEventResponse.java | 43 +++++ .../src/main/resources/application.properties | 42 +++++ .../migration/V20210823115500__create_index | 4 + .../test/java/org/egov/TestConfiguration.java | 16 ++ .../controllers/FiscalApiControllerTest.java | 57 +++++++ 29 files changed, 1363 insertions(+) create mode 100644 domain-services/fiscal-event-service/.gitignore create mode 100644 domain-services/fiscal-event-service/README.md create mode 100644 domain-services/fiscal-event-service/pom.xml create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/Main.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/config/FiscalEventConfiguration.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/config/MainConfiguration.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/repository/ServiceRequestRepository.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventEnrichmentService.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Amount.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Criteria.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventGetRequest.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventRequest.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java create mode 100644 domain-services/fiscal-event-service/src/main/resources/application.properties create mode 100644 domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index create mode 100644 domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java create mode 100644 domain-services/fiscal-event-service/src/test/java/org/egov/web/controllers/FiscalApiControllerTest.java diff --git a/domain-services/fiscal-event-service/.gitignore b/domain-services/fiscal-event-service/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/domain-services/fiscal-event-service/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/domain-services/fiscal-event-service/README.md b/domain-services/fiscal-event-service/README.md new file mode 100644 index 00000000..3047cadc --- /dev/null +++ b/domain-services/fiscal-event-service/README.md @@ -0,0 +1 @@ +# Fiscal-Event-Service \ No newline at end of file diff --git a/domain-services/fiscal-event-service/pom.xml b/domain-services/fiscal-event-service/pom.xml new file mode 100644 index 00000000..c810250d --- /dev/null +++ b/domain-services/fiscal-event-service/pom.xml @@ -0,0 +1,95 @@ + + 4.0.0 + org.egov + fiscal-event-service + jar + fiscal-event-service + 1.0.0 + + 1.8 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + + + org.egov.services + ifix-services-common + 0.0.1-SNAPSHOT + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/Main.java b/domain-services/fiscal-event-service/src/main/java/org/egov/Main.java new file mode 100644 index 00000000..fca48a16 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/Main.java @@ -0,0 +1,17 @@ +package org.egov; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = {"org.egov", "org.egov.web.controllers", "org.egov.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/config/FiscalEventConfiguration.java b/domain-services/fiscal-event-service/src/main/java/org/egov/config/FiscalEventConfiguration.java new file mode 100644 index 00000000..a9aa1ff8 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/config/FiscalEventConfiguration.java @@ -0,0 +1,58 @@ +package org.egov.config; + +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Import; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +public class FiscalEventConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Value("${fiscal.kafka.push.topic}") + private String fiscalPushRequest; + + @Value("${ifix.master.coa.host}") + private String ifixMasterCoaHost; + + @Value("${ifix.master.coa.context.path}") + private String ifixMasterCoaContextPath; + + @Value("${ifix.master.coa.search.path}") + private String ifixMasterCoaSearchPath; + + @Value("${ifix.master.government.host}") + private String ifixMasterGovernmentHost; + + @Value("${ifix.master.government.context.path}") + private String ifixMasterGovernmentContextPath; + + @Value("${ifix.master.government.search.path}") + private String ifixMasterGovernmentSearchPath; + + @Value("${ifix.master.project.host}") + private String ifixMasterProjectHost; + + @Value("${ifix.master.project.context.path}") + private String ifixMasterProjectContextPath; + + @Value("${ifix.master.project.search.path}") + private String ifixMasterProjectSearchPath; +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/config/MainConfiguration.java b/domain-services/fiscal-event-service/src/main/java/org/egov/config/MainConfiguration.java new file mode 100644 index 00000000..e4d1cb86 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/config/MainConfiguration.java @@ -0,0 +1,39 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java b/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java new file mode 100644 index 00000000..f00e15b4 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java @@ -0,0 +1,20 @@ +package org.egov.producer; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.tracer.kafka.CustomKafkaTemplate; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class Producer { + + @Autowired + private CustomKafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java new file mode 100644 index 00000000..5d764384 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java @@ -0,0 +1,10 @@ +package org.egov.repository; + + +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Repository; + +@Repository +@Slf4j +public class FiscalEventRepository { +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/ServiceRequestRepository.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/ServiceRequestRepository.java new file mode 100644 index 00000000..edb6ecb1 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/ServiceRequestRepository.java @@ -0,0 +1,49 @@ +package org.egov.repository; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Component +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + /** + * @param uri + * @param request + * @return + */ + public Object fetchResult(String uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri, request, Map.class); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); + } + + return response; + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventEnrichmentService.java b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventEnrichmentService.java new file mode 100644 index 00000000..28249337 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventEnrichmentService.java @@ -0,0 +1,54 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.FiscalEventUtil; +import org.egov.web.models.Amount; +import org.egov.web.models.FiscalEvent; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.BeanUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +@Service +@Slf4j +public class FiscalEventEnrichmentService { + + @Autowired + private FiscalEventUtil fiscalEventUtil; + + + public void enrichFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { + RequestHeader requestHeader = fiscalEventRequest.getRequestHeader(); + FiscalEvent fiscalEvent = fiscalEventRequest.getFiscalEvent(); + //set the id + fiscalEvent.setId(UUID.randomUUID().toString()); + + List amounts = new ArrayList<>(); + for (Amount amount : fiscalEvent.getAmountDetails()) { + Amount newAmount = new Amount(); + BeanUtils.copyProperties(amount, newAmount); + //set the amount id + newAmount.setId(UUID.randomUUID().toString()); + amounts.add(newAmount); + } + fiscalEvent.setAmountDetails(amounts); + + AuditDetails auditDetails = null; + if (fiscalEvent.getAuditDetails() == null) { + auditDetails = fiscalEventUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), fiscalEvent.getAuditDetails(), true); + } else { + auditDetails = fiscalEventUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), fiscalEvent.getAuditDetails(), false); + } + + //set the audit details + fiscalEvent.setAuditDetails(auditDetails); + fiscalEvent.setIngestionTime(System.currentTimeMillis()); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java new file mode 100644 index 00000000..431197d4 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java @@ -0,0 +1,40 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.config.FiscalEventConfiguration; +import org.egov.producer.Producer; +import org.egov.validator.FiscalEventValidator; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class FiscalEventService { + + @Autowired + private FiscalEventValidator validator; + + @Autowired + private FiscalEventEnrichmentService enricher; + + @Autowired + private Producer producer; + + @Autowired + private FiscalEventConfiguration eventConfiguration; + + + /** + * Validate , enrich and push the fiscal Event request to topic + * @param fiscalEventRequest + * @return + */ + public FiscalEventRequest fiscalEventsV1PushPost(FiscalEventRequest fiscalEventRequest) { + validator.validateFiscalEventPushPost(fiscalEventRequest); + enricher.enrichFiscalEventPushPost(fiscalEventRequest); + producer.push(eventConfiguration.getFiscalPushRequest(),fiscalEventRequest); + return fiscalEventRequest; + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java new file mode 100644 index 00000000..13e69b8c --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java @@ -0,0 +1,76 @@ +package org.egov.util; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.FiscalEventConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.Amount; +import org.egov.web.models.FiscalEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +@Slf4j +public class CoaUtil { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private FiscalEventConfiguration configuration; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + /** + * Get the COA Details from master data service + * @param requestHeader + * @param fiscalEvent + * @return + */ + public List getCOAIdsFromCOAService(RequestHeader requestHeader, FiscalEvent fiscalEvent) { + String url = createCoaSearchUrl(); + Map coaSearchRequest = createSearchCoaRequest(requestHeader, fiscalEvent); + + Object response = serviceRequestRepository.fetchResult(url,coaSearchRequest); + List responseCoaIds = null; + try{ + responseCoaIds = JsonPath.read(response, MasterDataConstants.COA_IDS_JSON_PATH); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse coa response for coaIds"); + } + return responseCoaIds; + } + + private Map createSearchCoaRequest(RequestHeader requestHeader, FiscalEvent fiscalEvent) { + if (!StringUtils.isEmpty(fiscalEvent.getTenantId())) { + List coaIds = new ArrayList<>(); + for (Amount amount : fiscalEvent.getAmountDetails()) { + coaIds.add(amount.getCoaId()); + } + Map coaSearchRequest = new HashMap<>(); + Map criteria = new HashMap<>(); + criteria.put("Ids", coaIds); + criteria.put("tenantId", fiscalEvent.getTenantId()); + + coaSearchRequest.put("requestHeader", requestHeader); + coaSearchRequest.put("criteria", criteria); + return coaSearchRequest; + } + + return Collections.emptyMap(); + } + + private String createCoaSearchUrl() { + StringBuilder uriBuilder = new StringBuilder(configuration.getIfixMasterCoaHost()) + .append(configuration.getIfixMasterCoaContextPath()).append(configuration.getIfixMasterCoaSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java new file mode 100644 index 00000000..cbf5a8f0 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java @@ -0,0 +1,32 @@ +package org.egov.util; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; + +@Component +@Slf4j +public class FiscalEventUtil { + + /** + * Method to return auditDetails of fiscal event request + * + * @param by + * @param isCreate + * @return AuditDetails + */ + public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { + Long time = System.currentTimeMillis(); + if(isCreate) + return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); + else + return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) + .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java new file mode 100644 index 00000000..be7ec835 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -0,0 +1,30 @@ +package org.egov.util; + +public class MasterDataConstants { + public static final String PROJECT_ID = "PROJECT_ID"; + public static final String JSONPATH_ERROR = "JSONPATH_ERROR"; + public static final String FISCAL_EVENT = "FISCAL_EVENT"; + public static final String REFERENCE_ID = "REFERENCE_ID"; + public static final String EVENT_TYPE = "EVENT_TYPE"; + + private MasterDataConstants() { + } + + public static final String IDS = "Ids"; + public static final String CRITERIA = "criteria"; + + public static final String GOVERNMENT_ID = "GOVERNMENT_ID"; + public static final String TENANT_ID = "TENANT_ID"; + public static final String EAT_ID = "EAT_ID"; + public static final String DEPARTMENT_ID = "DEPARTMENT_ID"; + public static final String LOCATION_ID = "LOCATION_ID"; + public static final String REQUEST_HEADER = "requestHeader"; + + public static final String CRITERIA_TENANT_ID = "tenantId"; + + public static final String TENANT_LIST = "$.government.*"; + public static final String PROJECT_LIST = "$.project.*"; + public static final String COA_IDS_JSON_PATH = "$.chartOfAccounts.*.id"; + + +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java new file mode 100644 index 00000000..5ebdace1 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java @@ -0,0 +1,64 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import org.apache.commons.lang3.StringUtils; +import org.egov.config.FiscalEventConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class ProjectUtil { + @Autowired + FiscalEventConfiguration fiscalEventConfiguration; + + @Autowired + ServiceRequestRepository serviceRequestRepository; + + /** + * @param fiscalEventRequest + * @return + */ + public boolean validateProjectId(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null + && fiscalEventRequest.getFiscalEvent() != null + && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getProjectId())) { + + Map projectValueMap = new HashMap<>(); + projectValueMap.put(MasterDataConstants.IDS, + Collections.singletonList(fiscalEventRequest.getFiscalEvent().getProjectId())); + projectValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, + fiscalEventRequest.getFiscalEvent().getTenantId()); + + Map ProjectMap = new HashMap<>(); + ProjectMap.put(MasterDataConstants.REQUEST_HEADER, fiscalEventRequest.getRequestHeader()); + ProjectMap.put(MasterDataConstants.CRITERIA, projectValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchProjectUrl(), ProjectMap); + + try{ + List list = JsonPath.read(response, MasterDataConstants.PROJECT_LIST); + + return list != null && !list.isEmpty(); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + } + } + return false; + } + + private String createSearchProjectUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(fiscalEventConfiguration.getIfixMasterProjectHost()) + .append(fiscalEventConfiguration.getIfixMasterProjectContextPath()) + .append(fiscalEventConfiguration.getIfixMasterProjectSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java new file mode 100644 index 00000000..c802136b --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -0,0 +1,26 @@ +package org.egov.util; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestHeader; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ResponseHeaderCreator { + + public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader requestInfo, final Boolean success) { + + final String correlationId = requestInfo != null ? requestInfo.getCorrelationId() : ""; + final String ver = requestInfo != null ? requestInfo.getVersion() : ""; + Long ts = null; + if (requestInfo != null) + ts = requestInfo.getTs(); + final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseHeader.builder().version(ver).ts(ts).msgId(msgId).correlationId(correlationId).signature(sign) + .status(responseStatus).build(); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java new file mode 100644 index 00000000..edb48d6b --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java @@ -0,0 +1,68 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.FiscalEventConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.*; + +@Component +@Slf4j +public class TenantUtil { + + @Autowired + FiscalEventConfiguration fiscalEventConfiguration; + + @Autowired + ServiceRequestRepository serviceRequestRepository; + + /** + * @param fiscalEventRequest + * @return + */ + public boolean validateTenant(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null + && fiscalEventRequest.getFiscalEvent() != null + && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getTenantId())) { + + Map tenantValueMap = new HashMap<>(); + tenantValueMap.put(MasterDataConstants.IDS, + Collections.singletonList(fiscalEventRequest.getFiscalEvent().getTenantId())); + + Map tenantMap = new HashMap<>(); + tenantMap.put(MasterDataConstants.REQUEST_HEADER, fiscalEventRequest.getRequestHeader()); + tenantMap.put(MasterDataConstants.CRITERIA, tenantValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchTenantUrl(), tenantMap); + + try{ + List list = JsonPath.read(response, MasterDataConstants.TENANT_LIST); + + return list != null && !list.isEmpty(); + }catch (Exception e){ + throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse government response for tenantId"); + } + } + return false; + } + + + /** + * @return + */ + private String createSearchTenantUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(fiscalEventConfiguration.getIfixMasterGovernmentHost()) + .append(fiscalEventConfiguration.getIfixMasterGovernmentContextPath()) + .append(fiscalEventConfiguration.getIfixMasterGovernmentSearchPath()); + return uriBuilder.toString(); + } + +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java new file mode 100644 index 00000000..4ea11a0a --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -0,0 +1,149 @@ +package org.egov.validator; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.EnumUtils; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.util.MasterDataConstants; +import org.egov.util.ProjectUtil; +import org.egov.util.TenantUtil; +import org.egov.util.CoaUtil; +import org.egov.web.models.Amount; +import org.egov.web.models.FiscalEvent; +import org.egov.web.models.FiscalEventRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.Map; + +import java.util.ArrayList; +import java.util.List; + +@Component +@Slf4j +public class FiscalEventValidator { + + + @Autowired + private CoaUtil coaUtil; + + @Autowired + TenantUtil tenantUtil; + + @Autowired + ProjectUtil projectUtil; + + /** + * Validate the fiscal Event request + * + * @param fiscalEventRequest + */ + public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { + if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null + && fiscalEventRequest.getFiscalEvent() != null) { + Map errorMap = new HashMap<>(); + + if (StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getReferenceId())) { + errorMap.put(MasterDataConstants.REFERENCE_ID, "Reference id is missing"); + } + + if (fiscalEventRequest.getFiscalEvent().getEventType() == null + || !EnumUtils.isValidEnum(FiscalEvent.EventTypeEnum.class, fiscalEventRequest.getFiscalEvent() + .getEventType().name())) { + + errorMap.put(MasterDataConstants.EVENT_TYPE, "Fical event type is missing"); + } + + validateReqHeader(fiscalEventRequest.getRequestHeader()); + validateTenantId(fiscalEventRequest, errorMap); + validateProjectId(fiscalEventRequest, errorMap); + validateFiscalEventAmountDetails(fiscalEventRequest, errorMap); + + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + + } else { + throw new CustomException(MasterDataConstants.FISCAL_EVENT, "Fiscal event request data is not valid"); + } + } + + /** + * Validate the request header + * + * @param requestHeader + */ + private void validateReqHeader(RequestHeader requestHeader) { + if (requestHeader == null) + throw new CustomException("REQUEST_HEADER", "Request header is missing"); + if (requestHeader.getUserInfo() == null) + throw new CustomException("USER_INFO", "User info is missing in request header"); + if (StringUtils.isBlank(requestHeader.getUserInfo().getUuid())) + throw new CustomException("USER_INFO", "User info is missing in request header"); + } + + + + /** + * Validate the fiscal event request - amount details(line items) attributes + * + * @param fiscalEventRequest + * @param errorMap + */ + private void validateFiscalEventAmountDetails(FiscalEventRequest fiscalEventRequest, Map errorMap) { + RequestHeader requestHeader = fiscalEventRequest.getRequestHeader(); + List amountDetails = fiscalEventRequest.getFiscalEvent().getAmountDetails(); + + if (amountDetails == null || amountDetails.isEmpty()) + errorMap.put("AMOUNT_DETAILS", "Amount details are missing"); + + List coaIds = new ArrayList<>(); + int amountDetailSize = amountDetails.size(); + int index = 1; + for (Amount amount : amountDetails) { + if (amount.getAmount() == null /*|| amount.getAmount().compareTo(BigDecimal.ZERO)==0*/) + errorMap.put("AMOUNT-" + index++, "Amount is missing for coaId : " + amount.getCoaId()); + if (StringUtils.isNotBlank(amount.getCoaId())) + coaIds.add(amount.getCoaId()); + } + + List responseCoaIds = coaUtil.getCOAIdsFromCOAService(requestHeader, fiscalEventRequest.getFiscalEvent()); + + List errorCoaIds = new ArrayList<>(); + for (String coaId : coaIds) { + if (!responseCoaIds.contains(coaId)) + errorCoaIds.add(coaId); + } + + if (!errorCoaIds.isEmpty()) { + errorMap.put("COA_ID_INVALID", "This chart of account id : " + errorCoaIds.toString() + " is invalid " + + "(or) Combination of tenant id with this chart of account id doesn't exist"); + } + } + + /** + * @param fiscalEventRequest + */ + public void validateTenantId(FiscalEventRequest fiscalEventRequest, Map errorMap) { + boolean isValidTenant = tenantUtil.validateTenant(fiscalEventRequest); + + if (!isValidTenant) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id doesn't exist in the system"); + } + } + + /** + * @param fiscalEventRequest + */ + public void validateProjectId(FiscalEventRequest fiscalEventRequest, Map errorMap) { + boolean isValidProject = projectUtil.validateProjectId(fiscalEventRequest); + + if (!isValidProject) { + errorMap.put(MasterDataConstants.PROJECT_ID, "Project id doesn't exist in the system"); + } + } + +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java new file mode 100644 index 00000000..a93b6cf2 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java @@ -0,0 +1,60 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.FiscalEventGetRequest; +import org.egov.web.models.FiscalEventRequest; +import org.egov.web.models.FiscalEventResponse; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; +import org.egov.service.FiscalEventService; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Collections; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Controller +@RequestMapping("/events/v1") +public class FiscalApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private FiscalEventService fiscalEventService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public FiscalApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_push", method = RequestMethod.POST) + public ResponseEntity fiscalEventsV1PushPost(@ApiParam(value = "Details for the new fiscal event + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody FiscalEventRequest body) { + FiscalEventRequest fiscalEventRequest = fiscalEventService.fiscalEventsV1PushPost(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + FiscalEventResponse fiscalEventResponse = FiscalEventResponse.builder().responseInfo(responseHeader) + .fiscalEvent(Collections.singletonList(fiscalEventRequest.getFiscalEvent())).build(); + return new ResponseEntity(fiscalEventResponse, HttpStatus.ACCEPTED); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity fiscalEventsV1SearchPost(@ApiParam(value = "RequestHeader meta data.", required = true) @Valid @RequestBody FiscalEventGetRequest body) { + return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + } + +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Amount.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Amount.java new file mode 100644 index 00000000..659ae37b --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Amount.java @@ -0,0 +1,40 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * Capture the transaction amount and chart of account corresponding to the transaction amount + */ +@ApiModel(description = "Capture the transaction amount and chart of account corresponding to the transaction amount") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Amount { + @JsonProperty("id") + private String id = null; + + @JsonProperty("amount") + private BigDecimal amount = null; + + @JsonProperty("coaId") + private String coaId = null; + + @JsonProperty("fromBillingPeriod") + private Long fromBillingPeriod = null; + + @JsonProperty("toBillingPeriod") + private Long toBillingPeriod = null; + + +} + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Criteria.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Criteria.java new file mode 100644 index 00000000..171e087a --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/Criteria.java @@ -0,0 +1,63 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of the fiscal events + */ +@ApiModel(description = "The object contains all the search criteria of the fiscal events") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class Criteria { + @JsonProperty("ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("eventType") + private String eventType = null; + + @JsonProperty("fromEventTime") + private Long fromEventTime = null; + + @JsonProperty("toEventTime") + private Long toEventTime = null; + + @JsonProperty("referenceId") + @Valid + private List referenceId = null; + + + public Criteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + + public Criteria addReferenceIdItem(String referenceIdItem) { + if (this.referenceId == null) { + this.referenceId = new ArrayList<>(); + } + this.referenceId.add(referenceIdItem); + return this; + } + +} + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java new file mode 100644 index 00000000..0010e1dc --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java @@ -0,0 +1,107 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonValue; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; +import java.util.UUID; + +/** + * This object captures the fiscal information of external systems. + */ +@ApiModel(description = "This object captures the fiscal information of external systems.") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEvent { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("projectId") + private String projectId = null; + + @JsonProperty("eventType") + private EventTypeEnum eventType = null; + + @JsonProperty("ingestionTime") + private Long ingestionTime = null; + + @JsonProperty("eventTime") + private Long eventTime = null; + + @JsonProperty("referenceId") + private String referenceId = null; + + @JsonProperty("parentEventId") + private String parentEventId = null; + + @JsonProperty("parentReferenceId") + private String parentReferenceId = null; + + @JsonProperty("amountDetails") + @Valid + private List amountDetails = new ArrayList<>(); + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + @JsonProperty("attributes") + private Object attributes = null; + + + public enum EventTypeEnum { + Sanction("Sanction"), + Appropriation("Appropriation"), + Allocation("Allocation"), + IntraTransfer("IntraTransfer"), + InterTransfer("InterTransfer"), + Demand("Demand"), + Receipt("Receipt"), + Bill("Bill"), + Payment("Payment"); + + private String value; + + EventTypeEnum(String value) { + this.value = value; + } + + @JsonCreator + public static EventTypeEnum fromValue(String text) { + for (EventTypeEnum eventTypeEnum : EventTypeEnum.values()) { + if (String.valueOf(eventTypeEnum.value).equals(text)) { + return eventTypeEnum; + } + } + return null; + } + + @Override + @JsonValue + public String toString() { + return String.valueOf(value); + } + } + + public FiscalEvent addAmountDetailsItem(Amount amountDetailsItem) { + this.amountDetails.add(amountDetailsItem); + return this; + } + +} + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventGetRequest.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventGetRequest.java new file mode 100644 index 00000000..cefd03be --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventGetRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Fiscal event request along with request metadata + */ +@ApiModel(description = "Fiscal event request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventGetRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private Criteria criteria = null; + + +} + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventRequest.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventRequest.java new file mode 100644 index 00000000..db1b8841 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventRequest.java @@ -0,0 +1,31 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + + +/** + * Fiscal event request along with request metadata + */ +@ApiModel(description = "Fiscal event request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("fiscalEvent") + private FiscalEvent fiscalEvent = null; + + +} + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java new file mode 100644 index 00000000..6a34f79a --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched fiscal information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched fiscal information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class FiscalEventResponse { + @JsonProperty("responseInfo") + private ResponseHeader responseInfo = null; + + @JsonProperty("fiscalEvent") + @Valid + private List fiscalEvent = null; + + + public FiscalEventResponse addFiscalEventItem(FiscalEvent fiscalEventItem) { + if (this.fiscalEvent == null) { + this.fiscalEvent = new ArrayList<>(); + } + this.fiscalEvent.add(fiscalEventItem); + return this; + } + +} + diff --git a/domain-services/fiscal-event-service/src/main/resources/application.properties b/domain-services/fiscal-event-service/src/main/resources/application.properties new file mode 100644 index 00000000..23a7021b --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/resources/application.properties @@ -0,0 +1,42 @@ +server.servlet.contextPath=/fiscal-event-service +server.port=8031 + +app.timezone=UTC + +org.egov.detailed.tracing.enabled=true + +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=localhost:9092 +#spring.kafka.consumer.value-deserializer=org.egov.boundary.consumer.HashMapDeserializer +#spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +#spring.kafka.consumer.group-id=egov-location +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer + +# KAFKA CONSUMER CONFIGURATIONS +#kafka.consumer.config.auto_commit=true +#kafka.consumer.config.auto_commit_interval=100 +#kafka.consumer.config.session_timeout=15000 +#kafka.consumer.config.auto_offset_reset=earliest + +# KAFKA PRODUCER CONFIGURATIONS +#kafka.producer.config.retries_config=0 +#kafka.producer.config.batch_size_config=16384 +#kafka.producer.config.linger_ms_config=1 +#kafka.producer.config.buffer_memory_config=33554432 + +## Kafka Topic Configurations ## +fiscal.kafka.push.topic=fiscal-event-request-validated + +## Uri Configurations ## +ifix.master.coa.host=http://localhost:8030 +ifix.master.coa.context.path=/ifix-master-data +ifix.master.coa.search.path=/chartOfAccount/v1/_search + +ifix.master.government.host=http://localhost:8030 +ifix.master.government.context.path=/ifix-master-data +ifix.master.government.search.path=/government/v1/_search + +ifix.master.project.host=http://localhost:8030 +ifix.master.project.context.path=/ifix-master-data +ifix.master.project.search.path=/project/v1/_search \ No newline at end of file diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index new file mode 100644 index 00000000..0d1b0b4f --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index @@ -0,0 +1,4 @@ +db.fiscalEvent.createIndexes( + [{"eventType":1},{"eventTime":1},{"tenantId":1},{"referenceId":1}] + ); +db.fiscalEvent.getIndexes(); diff --git a/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java b/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/fiscal-event-service/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/domain-services/fiscal-event-service/src/test/java/org/egov/web/controllers/FiscalApiControllerTest.java b/domain-services/fiscal-event-service/src/test/java/org/egov/web/controllers/FiscalApiControllerTest.java new file mode 100644 index 00000000..0c54a66c --- /dev/null +++ b/domain-services/fiscal-event-service/src/test/java/org/egov/web/controllers/FiscalApiControllerTest.java @@ -0,0 +1,57 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for FiscalApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(FiscalApiController.class) +@Import(TestConfiguration.class) +public class FiscalApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void fiscalEventsV1PushPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Fiscal-Event/1.0.0/fiscal/events/v1/_push").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void fiscalEventsV1PushPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Fiscal-Event/1.0.0/fiscal/events/v1/_push").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void fiscalEventsV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Fiscal-Event/1.0.0/fiscal/events/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void fiscalEventsV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Fiscal-Event/1.0.0/fiscal/events/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} From b46659d6be08f4ef7084391624d62b22fe3573d7 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:21:23 +0530 Subject: [PATCH 09/67] Ifix zuul (#30) * Update build-config.yml (#3) * Update build-config.yml (#4) * Update build-config.yml (#5) * ifix-zuul: Copy from DIGIT Zuul * Code cleanup * Updated Dockerfile base image (#6) * Update build-config.yml (#12) * Jwt Verifier Filter * Refactored: requestInfo -> requestHeader and responseInfo -> responseHeader * Commented out all unused filters * Reformat Code * Refactor REQUEST_INFO -> REQUEST_HEADER * Added userInfo to requestHeader by reading it from JWT. * Bug Fixed * Commented out unused filter * Bug fixed * Removed unused filter * Resolve test cases Co-authored-by: rushang7-eGov Co-authored-by: Rushang Dhanesha Co-authored-by: pintu-eGov --- core/ifix-zuul/.editorconfig | 5 + core/ifix-zuul/.gitignore | 42 +++ core/ifix-zuul/CHANGELOG.md | 32 ++ core/ifix-zuul/LOCALSETUP.md | 34 ++ core/ifix-zuul/README.md | 93 +++++ core/ifix-zuul/pom.xml | 155 ++++++++ .../src/main/java/org/egov/UrlProvider.java | 82 +++++ .../org/egov/Utils/CustomRateLimitUtils.java | 62 ++++ .../java/org/egov/Utils/EventLoggerUtil.java | 49 +++ .../java/org/egov/Utils/ExceptionUtils.java | 140 +++++++ .../src/main/java/org/egov/Utils/JwtUtil.java | 39 ++ .../main/java/org/egov/Utils/UserUtils.java | 67 ++++ .../src/main/java/org/egov/Utils/Utils.java | 48 +++ .../java/org/egov/ZuulGatewayApplication.java | 104 ++++++ .../java/org/egov/config/Configuration.java | 49 +++ .../config/KeycloakJwtVerifierConfig.java | 53 +++ .../constants/RequestContextConstants.java | 31 ++ .../main/java/org/egov/contract/Action.java | 37 ++ .../src/main/java/org/egov/contract/Role.java | 31 ++ .../src/main/java/org/egov/contract/User.java | 101 +++++ .../main/java/org/egov/contract/UserInfo.java | 35 ++ .../org/egov/exceptions/CustomException.java | 17 + .../egov/filters/error/ErrorFilterFilter.java | 34 ++ .../egov/filters/post/CustomAsyncFilter.java | 106 ++++++ .../egov/filters/post/PostEventLogFilter.java | 53 +++ .../org/egov/filters/post/PostHookFilter.java | 111 ++++++ .../post/ResponseEnhancementFilter.java | 51 +++ .../filters/post/ResponseErrorFilter.java | 42 +++ .../java/org/egov/filters/pre/AuthFilter.java | 81 +++++ .../egov/filters/pre/AuthPreCheckFilter.java | 212 +++++++++++ .../egov/filters/pre/CorrelationIdFilter.java | 50 +++ .../filters/pre/JwtAuthenticationFilter.java | 72 ++++ .../org/egov/filters/pre/PreHookFilter.java | 96 +++++ .../java/org/egov/filters/pre/RbacFilter.java | 191 ++++++++++ .../egov/filters/pre/RbacPreCheckFilter.java | 67 ++++ .../filters/pre/RequestEnrichmentFilter.java | 170 +++++++++ .../filters/pre/RequestStartTimeFilter.java | 32 ++ .../org/egov/kafka/HashMapDeserializer.java | 16 + .../org/egov/model/AuthorizationRequest.java | 29 ++ .../model/AuthorizationRequestWrapper.java | 22 ++ .../org/egov/model/CustomAsyncRequest.java | 25 ++ .../java/org/egov/model/EventLogRequest.java | 144 ++++++++ .../org/egov/model/PostHookFilterRequest.java | 18 + .../org/egov/model/PreHookFilterRequest.java | 16 + .../org/egov/model/RequestBodyInspector.java | 58 +++ .../egov/model/RequestCaptureCriteria.java | 16 + .../org/egov/model/UserDetailResponse.java | 23 ++ .../org/egov/model/UserSearchRequest.java | 50 +++ .../main/java/org/egov/producer/Producer.java | 18 + .../org/egov/revenues/PropertyUtility.java | 10 + .../egov/wrapper/CustomRequestWrapper.java | 51 +++ .../src/main/resources/application.properties | 64 ++++ .../src/main/resources/limiter.properties | 50 +++ .../src/main/resources/routes.properties | 279 ++++++++++++++ .../src/test/java/org/egov/Resources.java | 22 ++ .../java/org/egov/contract/ActionTest.java | 19 + .../post/ResponseEnhancementFilterTest.java | 67 ++++ .../org/egov/filters/pre/AuthFilterTest.java | 86 +++++ .../filters/pre/AuthPreCheckFilterTest.java | 344 ++++++++++++++++++ .../filters/pre/CorrelationIdFilterTest.java | 55 +++ .../org/egov/filters/pre/RbacFilterTest.java | 201 ++++++++++ .../filters/pre/RbacPreCheckFilterTest.java | 67 ++++ .../pre/RequestEnrichmentFilterTest.java | 150 ++++++++ .../egov/model/RequestBodyInspectorTest.java | 89 +++++ .../wrapper/CustomRequestWrapperTest.java | 57 +++ .../src/test/resources/application.properties | 59 +++ .../test/resources/enrichedPostRequest.json | 13 + .../resources/postRequestFromConsumer.json | 6 + .../postRequestWithCorrelationId.json | 7 + ...questWithoutRequestHeaderFromConsumer.json | 5 + .../src/test/resources/userInfoHeader.json | 6 + 71 files changed, 4816 insertions(+) create mode 100644 core/ifix-zuul/.editorconfig create mode 100644 core/ifix-zuul/.gitignore create mode 100644 core/ifix-zuul/CHANGELOG.md create mode 100644 core/ifix-zuul/LOCALSETUP.md create mode 100644 core/ifix-zuul/README.md create mode 100644 core/ifix-zuul/pom.xml create mode 100644 core/ifix-zuul/src/main/java/org/egov/UrlProvider.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/CustomRateLimitUtils.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/EventLoggerUtil.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/ExceptionUtils.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/JwtUtil.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/UserUtils.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/Utils/Utils.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/ZuulGatewayApplication.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/config/Configuration.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/config/KeycloakJwtVerifierConfig.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/constants/RequestContextConstants.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/contract/Action.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/contract/Role.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/contract/User.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/contract/UserInfo.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/exceptions/CustomException.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/error/ErrorFilterFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/post/CustomAsyncFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/post/PostEventLogFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/post/PostHookFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseEnhancementFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseErrorFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthPreCheckFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/CorrelationIdFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/JwtAuthenticationFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/PreHookFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacPreCheckFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestEnrichmentFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestStartTimeFilter.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/kafka/HashMapDeserializer.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequestWrapper.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/CustomAsyncRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/EventLogRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/PostHookFilterRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/PreHookFilterRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/RequestBodyInspector.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/RequestCaptureCriteria.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/UserDetailResponse.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/model/UserSearchRequest.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/producer/Producer.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/revenues/PropertyUtility.java create mode 100644 core/ifix-zuul/src/main/java/org/egov/wrapper/CustomRequestWrapper.java create mode 100644 core/ifix-zuul/src/main/resources/application.properties create mode 100644 core/ifix-zuul/src/main/resources/limiter.properties create mode 100644 core/ifix-zuul/src/main/resources/routes.properties create mode 100644 core/ifix-zuul/src/test/java/org/egov/Resources.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/contract/ActionTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/post/ResponseEnhancementFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthPreCheckFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/CorrelationIdFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacPreCheckFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/filters/pre/RequestEnrichmentFilterTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/model/RequestBodyInspectorTest.java create mode 100644 core/ifix-zuul/src/test/java/org/egov/wrapper/CustomRequestWrapperTest.java create mode 100644 core/ifix-zuul/src/test/resources/application.properties create mode 100644 core/ifix-zuul/src/test/resources/enrichedPostRequest.json create mode 100644 core/ifix-zuul/src/test/resources/postRequestFromConsumer.json create mode 100644 core/ifix-zuul/src/test/resources/postRequestWithCorrelationId.json create mode 100644 core/ifix-zuul/src/test/resources/postRequestWithoutRequestHeaderFromConsumer.json create mode 100644 core/ifix-zuul/src/test/resources/userInfoHeader.json diff --git a/core/ifix-zuul/.editorconfig b/core/ifix-zuul/.editorconfig new file mode 100644 index 00000000..93e147aa --- /dev/null +++ b/core/ifix-zuul/.editorconfig @@ -0,0 +1,5 @@ +root = true + +[*] +indent_style = space +indent_size = 4 \ No newline at end of file diff --git a/core/ifix-zuul/.gitignore b/core/ifix-zuul/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/core/ifix-zuul/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/core/ifix-zuul/CHANGELOG.md b/core/ifix-zuul/CHANGELOG.md new file mode 100644 index 00000000..cb542e9b --- /dev/null +++ b/core/ifix-zuul/CHANGELOG.md @@ -0,0 +1,32 @@ +All notable changes to this module will be documented in this file. + +## 1.3.0 - 2021-05-17 + +- Changes to error handling +- Removed stack trace printing +- Added rate limiting functionality +- Add support for PATCH and PUT statements +- Changed auth filter to not read body if Json content type is not specified +- Removed `x-user-info` header from sensitive headers in `application.properties` + +## 1.2.1 - 2021-02-26 + +- Updated domain name in routes.properties + +## 1.2.0 - 2021-01-12 + +- ZUUL METRIC CAPTURING ADDED + +## 1.2.0 + +## 1.1.0 - 2020-06-22 + +- Added typescript definition generation plugin +- Upgraded to `tracer:2.0.0-SNAPSHOT` +- Upgraded to spring boot `2.2.6-RELEASE` +- Upgraded to spring-cloud-starter-netflix-zuul `2.2.2.RELEASE` +- Deleted `Dockerfile` and `start.sh` as it is no longer in use + +## 1.0.0 + +- Base version diff --git a/core/ifix-zuul/LOCALSETUP.md b/core/ifix-zuul/LOCALSETUP.md new file mode 100644 index 00000000..d4fd788e --- /dev/null +++ b/core/ifix-zuul/LOCALSETUP.md @@ -0,0 +1,34 @@ +# Local Setup + +To setup the Zuul service in your local system, clone +the [Core Service repository](https://github.com/egovernments/core-services). + +## Dependencies + +### Infra Dependency + +- [ ] Postgres DB +- [ ] Redis +- [ ] Elasticsearch +- [ ] Kafka + - [ ] Consumer + - [ ] Producer + +## Running Locally + +To run the Zuul services in your local system, you need to port forward below services + +```bash +function kgpt(){kubectl get pods -n egov --selector=app=$1 --no-headers=true | head -n1 | awk '{print $1}'} +kubectl port-forward -n egov $(kgpt egov-accesscontrol) 8087:8080 +kubectl port-forward -n egov $(kgpt egov-user) 8088:8080 +``` + +Update below listed properties in **`application.properties`** before running the project: + +```ini +egov.auth-service-host = http://127.0.0.1:8088 +egov.authorize.access.control.host = http://127.0.0.1:8087 +# If you are using a local file prefix it with file:///PATH TO FILE/FILENAME +zuul.routes.filepath = {path of file which contain the routing information of each modules} +``` diff --git a/core/ifix-zuul/README.md b/core/ifix-zuul/README.md new file mode 100644 index 00000000..76c52c29 --- /dev/null +++ b/core/ifix-zuul/README.md @@ -0,0 +1,93 @@ +# Zuul Service + +### API Gateway + +API Gateway provides a unified interface for a set of microservices so that clients do not need to know about all the +details of microservices internals. + +Digit uses Zuul as an edge service that proxies requests to multiple back-end services. It provides a unified “front +door” to our ecosystem. This allows any browser, mobile app or other user interface to consume underlying services. + +### DB UML Diagram + +- NA + +### Service Dependencies + +- egov-accesscontrol +- egov-user + +### Swagger API Contract + +- NA + +## Service Details + +**DIGIT** uses **Netflix ZUUL** as API Gateway. + +**Functionality** + +- Provides easier API interface to clients +- Can be used to prevent exposing the internal micro-services structure to outside world. +- Allows to refactor microservices without forcing the clients to refactor consuming logic +- Can centralize cross-cutting concerns like security, monitoring, rate limiting etc + +**ZUUL Components** + +Zuul has mainly four types of filters that enable us to intercept the traffic in different timeline of the request +processing for any particular transaction. We can add any number of filters for a particular url pattern. + +- pre filters – are invoked before the request is routed. +- post filters – are invoked after the request has been routed. +- route filters – are used to route the request. +- error filters – are invoked when an error occurs while handling the request. + +**Features** + +- Microservice authentication and security +- Authorization +- API Routing +- Open APIs using Whitelisting +- RBAC filter +- Logout filter for finance module +- Property module tax calculation filter for firecess +- Request enrichment filter: +- Addition of co-relation id +- Addition of authenticated user’s userinfo to requestHeader. +- Error filter: + - Error response formatting +- Validation Filter to check if a tenant of a particular module is enabled or not. +- Multitenancy Validation Filter. Take the tenant id from Req body or Query Param and validate against additional tenant + role or primary tenant role. +- Devops efficiency: API Response time logging and Send notification if it is taking more time. +- Rate Throttling + +**Routing Property** + +For each service, below mentioned property has to be add in **`routes.properties`** + +```ini +-zuul.routes.{serviceName}.path = /{context path of service}/** +-zuul.routes.{serviceName}.stripPrefix = {true/false} +-zuul.routes.{serviceName}.url = {service host name} +``` + +**Rate Limiting Property** + +For endpoints which requires rate throttling, below mentioned property has to be added in **`limiter.properties`** + +```ini +-zuul.ratelimit.policy-list.{serviceName}[0].limit={request number limit per refresh interval window} +-zuul.ratelimit.policy-list.{serviceName}[0].quota={request time limit per refresh interval window (in seconds)} +-zuul.ratelimit.policy-list.{serviceName}[0].refresh-interval={refresh interval in seconds} +-zuul.ratelimit.policy-list.{serviceName}[0].type[0]=url={url of API endpoint} +-zuul.ratelimit.policy-list.{serviceName}[0].type[1]={type of throttling eg: user, origin etc.} +``` + +### Kafka Consumers + +- NA + +### Kafka Producers + +- NA diff --git a/core/ifix-zuul/pom.xml b/core/ifix-zuul/pom.xml new file mode 100644 index 00000000..4087bdf8 --- /dev/null +++ b/core/ifix-zuul/pom.xml @@ -0,0 +1,155 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + org.egov + ifix-zuul + 0.0.1-SNAPSHOT + ifix-zuul + Api gateway for iFIX + + UTF-8 + 1.8 + UTF-8 + 1.18.8 + + + + + com.auth0 + java-jwt + 3.18.1 + + + + org.springframework.cloud + spring-cloud-starter-netflix-zuul + 2.2.2.RELEASE + + + com.netflix.netflix-commons + netflix-commons-util + 0.3.0 + + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + + + org.springframework.boot + spring-boot-starter-test + test + + + com.jayway.jsonpath + json-path + + + org.projectlombok + lombok + true + + + org.apache.commons + commons-io + 1.3.2 + + + com.marcosbarbero.cloud + spring-cloud-zuul-ratelimit + 2.4.0.RELEASE + + + org.springframework.boot + spring-boot-starter-data-redis + + + org.springframework.kafka + spring-kafka + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-devtools + + + + + + + cz.habarta.typescript-generator + typescript-generator-maven-plugin + 2.22.595 + + + generate + + generate + + process-classes + + + + jackson2 + + org.egov.model.AuthorizationRequestWrapper + org.egov.model.UserDetailResponse + org.egov.model.UserSearchRequest + + + org.egov.common.contract.request.RequestHeader:RequestHeader + + org.egov.common.contract.response.ResponseHeader:ResponseHeader + + + Digit + true + module + + + + + diff --git a/core/ifix-zuul/src/main/java/org/egov/UrlProvider.java b/core/ifix-zuul/src/main/java/org/egov/UrlProvider.java new file mode 100644 index 00000000..e99a65b4 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/UrlProvider.java @@ -0,0 +1,82 @@ +package org.egov; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang.StringUtils; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.core.io.Resource; +import org.springframework.core.io.ResourceLoader; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.io.IOException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +@Component +@Slf4j +public class UrlProvider { + + + private static Map urlPostHooksMap; + private static Map urlPreHooksMap; + @Autowired + private ResourceLoader resourceLoader; + @Value("${url.posthook.lists}") + private String postHookUrls; + @Value("${url.prehook.lists}") + private String preHookUrls; + + public static Map getUrlPostHooksMap() { + return urlPostHooksMap; + } + + public static Map getUrlPreHooksMap() { + return urlPreHooksMap; + } + + private Map getUrlToUrlMapping(String config) { + String[] urlArray; + Map map = new HashMap<>(); + if (StringUtils.isEmpty(config)) + return Collections.unmodifiableMap(map); + + if ( + StringUtils.startsWithIgnoreCase(config, "http://") + || StringUtils.startsWithIgnoreCase(config, "https://") + || StringUtils.startsWithIgnoreCase(config, "file://") + || StringUtils.startsWithIgnoreCase(config, "classpath:") + ) { + ObjectMapper mapper = new ObjectMapper(new JsonFactory()); + + Resource resource = resourceLoader.getResource(config); + try { + map = mapper.readValue(resource.getInputStream(), map.getClass()); + } catch (IOException e) { + log.error("IO Exception while mapping resource: " + e.getMessage()); + } + + } else { + urlArray = config.split("\\|"); + + for (int i = 0; i < urlArray.length; i++) { + + String[] index = urlArray[i].split(":", 2); + map.put(index[0], index[1]); + } + urlPostHooksMap = Collections.unmodifiableMap(map); + } + + return Collections.unmodifiableMap(map); + } + + @PostConstruct + public void loadUrls() { + urlPostHooksMap = getUrlToUrlMapping(postHookUrls); + urlPreHooksMap = getUrlToUrlMapping(preHookUrls); + + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/CustomRateLimitUtils.java b/core/ifix-zuul/src/main/java/org/egov/Utils/CustomRateLimitUtils.java new file mode 100644 index 00000000..837f09b0 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/CustomRateLimitUtils.java @@ -0,0 +1,62 @@ +package org.egov.Utils; + + +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties; +import com.netflix.zuul.context.RequestContext; +import org.egov.contract.User; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.servlet.http.HttpServletRequest; +import java.util.Set; + +import static org.egov.constants.RequestContextConstants.USER_INFO_KEY; +import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.X_FORWARDED_FOR_HEADER; + +@Component +public class CustomRateLimitUtils implements RateLimitUtils { + + + private static final String UUID_JSON_PATH = "$.requestHeader.userInfo.uuid"; + private static final String ANONYMOUS_USER = "anonymous"; + private static final String X_FORWARDED_FOR_HEADER_DELIMITER = ","; + + private final RateLimitProperties properties; + + public CustomRateLimitUtils(RateLimitProperties properties) { + this.properties = properties; + } + + @PostConstruct + void changeFilterOrder() { + properties.setPreFilterOrder(10); + } + + @Override + public String getUser(final HttpServletRequest request) { + RequestContext ctx = RequestContext.getCurrentContext(); + try { + User user = (User) ctx.get(USER_INFO_KEY); + if (user != null) + return user.getUuid(); + } catch (Exception e) { + e.printStackTrace(); + } + return null; + } + + @Override + public String getRemoteAddress(final HttpServletRequest request) { + String xForwardedFor = request.getHeader(X_FORWARDED_FOR_HEADER); + if (properties.isBehindProxy() && xForwardedFor != null) { + return xForwardedFor.split(X_FORWARDED_FOR_HEADER_DELIMITER)[0].trim(); + } + return request.getRemoteAddr(); + } + + @Override + public Set getUserRoles() { + throw new UnsupportedOperationException("Not supported"); + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/EventLoggerUtil.java b/core/ifix-zuul/src/main/java/org/egov/Utils/EventLoggerUtil.java new file mode 100644 index 00000000..b958c2a7 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/EventLoggerUtil.java @@ -0,0 +1,49 @@ +package org.egov.Utils; + +import com.netflix.zuul.context.RequestContext; +import lombok.extern.slf4j.Slf4j; +import org.egov.model.EventLogRequest; +import org.egov.model.RequestCaptureCriteria; +import org.egov.producer.Producer; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; + +@Component +@Slf4j +public class EventLoggerUtil { + @Autowired + Producer producer; + + @Value("${eventlog.captureInputBody:false}") + private boolean captureInputBody; + + @Value("${eventlog.captureOutputBody:false}") + private boolean captureOutputBody; + + @Value("${eventlog.captureOutputBodyOnlyOnError:true}") + private boolean captureOutputBodyOnlyOnError; + + private RequestCaptureCriteria criteria; + + @PostConstruct + public void init() { + criteria = RequestCaptureCriteria.builder() + .captureInputBody(captureInputBody) + .captureOutputBody(captureOutputBody) + .captureOutputBodyOnlyForError(captureOutputBodyOnlyOnError) + .build(); + } + + public Object logCurrentRequest(String topic) { + try { + EventLogRequest request = EventLogRequest.fromRequestContext(RequestContext.getCurrentContext(), criteria); + producer.push(topic, request); + } catch (Exception ex) { + log.error("event logger", ex); + } + return null; + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/ExceptionUtils.java b/core/ifix-zuul/src/main/java/org/egov/Utils/ExceptionUtils.java new file mode 100644 index 00000000..31481c8a --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/ExceptionUtils.java @@ -0,0 +1,140 @@ +package org.egov.Utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.egov.exceptions.CustomException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.web.client.HttpClientErrorException; + +import java.io.IOException; +import java.util.HashMap; +import java.util.List; + +public class ExceptionUtils { + private static final Logger logger = LoggerFactory.getLogger(ExceptionUtils.class); + private static final String SEND_ERROR_FILTER_RAN = "sendErrorFilter.ran"; + + private static String getObjectJSONString(Object obj) throws JsonProcessingException { + return new ObjectMapper().writeValueAsString(obj); + } + + private static HashMap getErrorInfoObject(String code, String message, String description) { + String errorTemplate = "{\n" + + " \"responseHeader\": null,\n" + + " \"Errors\": [\n" + + " {\n" + + " \"code\": \"Exception\",\n" + + " \"message\": null,\n" + + " \"description\": null,\n" + + " \"params\": null\n" + + " }\n" + + " ]\n" + + "}"; + ObjectMapper objectMapper = new ObjectMapper(); + try { + HashMap errorInfo = objectMapper.readValue(errorTemplate, new TypeReference>() { + }); + HashMap error = (HashMap) ((List) errorInfo.get("Errors")).get(0); + error.put("code", code); + error.put("message", message); + error.put("description", description); + return errorInfo; + } catch (IOException e) { + logger.error("IO Exception while getting errorInfo object: " + e.getMessage()); + } + + return null; + } + + public static void setCustomException(HttpStatus status, String message) { + try { + _setExceptionBody(status, getErrorInfoObject("CustomException", message, message)); + } catch (JsonProcessingException e) { + e.printStackTrace(); + } + } + + private static void _setExceptionBody(HttpStatus status, Object body) throws JsonProcessingException { + _setExceptionBody(status, getObjectJSONString(body)); + } + + private static void _setExceptionBody(HttpStatus status, String body) { + RequestContext ctx = RequestContext.getCurrentContext(); + + ctx.setSendZuulResponse(false); + ctx.setResponseStatusCode(status.value()); + ctx.getResponse().setContentType("application/json"); + if (body == null) + body = "{}"; + ctx.setResponseBody(body); + ctx.remove("error.status_code"); + ctx.set(SEND_ERROR_FILTER_RAN); + ctx.remove("throwable"); + } + + public static void RaiseException(Throwable ex) { + throw new RuntimeException(ex); + } + + public static void raiseCustomException(HttpStatus status, String message) { + throw new RuntimeException(new CustomException(message, status.value(), "CustomException")); + } + + public static void raiseErrorFilterException(RequestContext ctx) { +// RequestContext ctx = RequestContext.getCurrentContext(); + Throwable e = ctx.getThrowable() == null ? (Throwable) ctx.get("error.exception") : ctx.getThrowable(); + + try { + if (e == null) { + if (ctx.getResponseStatusCode() == HttpStatus.NOT_FOUND.value()) { + _setExceptionBody(HttpStatus.NOT_FOUND, getErrorInfoObject("ResourceNotFoundException", + "The resource - " + ctx.getRequest().getRequestURI() + " not found", null)); + } else if (ctx.getResponseStatusCode() == HttpStatus.BAD_REQUEST.value()) { + String existingResponse = Utils.getResponseBody(ctx); + + if (existingResponse != null && existingResponse.contains("InvalidAccessTokenException")) + _setExceptionBody(HttpStatus.UNAUTHORIZED, existingResponse); + } + return; + } + + while ((e instanceof ZuulException || e.getClass().equals(RuntimeException.class)) && e.getCause() != null) + e = e.getCause(); + + String exceptionName = e.getClass().getSimpleName(); + String exceptionMessage = ((Throwable) e).getMessage(); + + if (exceptionName.equalsIgnoreCase("HttpHostConnectException") || + exceptionName.equalsIgnoreCase("ResourceAccessException")) { + _setExceptionBody(HttpStatus.BAD_GATEWAY, getErrorInfoObject(exceptionName, "The backend service is unreachable", null)); + } else if (exceptionName.equalsIgnoreCase("NullPointerException")) { + e.printStackTrace(); + _setExceptionBody(HttpStatus.INTERNAL_SERVER_ERROR, getErrorInfoObject(exceptionName, exceptionMessage, exceptionMessage)); + } else if (exceptionName.equalsIgnoreCase("HttpClientErrorException")) { + String existingResponse = ((HttpClientErrorException) e).getResponseBodyAsString(); + if (existingResponse.contains("InvalidAccessTokenException")) + _setExceptionBody(HttpStatus.UNAUTHORIZED, existingResponse); + else + _setExceptionBody(((HttpClientErrorException) e).getStatusCode(), existingResponse); + } else if (exceptionName.equalsIgnoreCase("InvalidAccessTokenException")) { + _setExceptionBody(HttpStatus.UNAUTHORIZED, getErrorInfoObject(exceptionName, exceptionMessage, exceptionMessage)); + } else if (exceptionName.equalsIgnoreCase("RateLimitExceededException")) { + _setExceptionBody(HttpStatus.TOO_MANY_REQUESTS, getErrorInfoObject(exceptionName, "Rate limit exceeded", null)); + } else if (exceptionName.equalsIgnoreCase("JsonParseException")) { + _setExceptionBody(HttpStatus.BAD_REQUEST, getErrorInfoObject(exceptionName, "Bad request", null)); + } else if (exceptionName.equalsIgnoreCase("CustomException")) { + CustomException ce = (CustomException) e; + _setExceptionBody(HttpStatus.valueOf(ce.nStatusCode), getErrorInfoObject(exceptionName, exceptionMessage, exceptionMessage)); + } else { + _setExceptionBody(HttpStatus.INTERNAL_SERVER_ERROR, getErrorInfoObject(exceptionName, exceptionMessage, exceptionMessage)); + } + } catch (Exception e1) { + logger.error("Exception while raising error filter exception: " + e1.getMessage()); + } + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/JwtUtil.java b/core/ifix-zuul/src/main/java/org/egov/Utils/JwtUtil.java new file mode 100644 index 00000000..ef0e8c10 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/JwtUtil.java @@ -0,0 +1,39 @@ +package org.egov.Utils; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import org.egov.contract.UserInfo; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +@Component +public class JwtUtil { + + @Autowired + private ObjectMapper objectMapper; + + public UserInfo createUserInfoFromJwt(String jwtPayload) throws JsonProcessingException { + JsonNode payload = objectMapper.readTree(jwtPayload); + UserInfo userInfo = UserInfo.builder().build(); + + userInfo.setUuid(payload.get("sub").asText()); + + ArrayNode arrayNode = (ArrayNode) payload.get("realm_access").get("roles"); + List roles = Arrays.asList(objectMapper.readValue(arrayNode.toString(), String[].class)); + userInfo.setRoles(roles); + + List tenants = new ArrayList<>(); + tenants.add(payload.get("tenantId").asText()); + userInfo.setTenants(tenants); + + return userInfo; + } + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/UserUtils.java b/core/ifix-zuul/src/main/java/org/egov/Utils/UserUtils.java new file mode 100644 index 00000000..4568066a --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/UserUtils.java @@ -0,0 +1,67 @@ +package org.egov.Utils; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.contract.User; +import org.egov.model.UserDetailResponse; +import org.egov.model.UserSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.cache.annotation.Cacheable; +import org.springframework.stereotype.Repository; +import org.springframework.util.CollectionUtils; +import org.springframework.web.client.RestTemplate; + +import java.util.Collections; + +@Slf4j +@Repository +public class UserUtils { + + + @Value("${egov.statelevel.tenant}") + private String stateLevelTenant; + + @Value("${egov.auth-service-host}${egov.user.search.path}") + private String userSearchURI; + + private RestTemplate restTemplate; + + private ObjectMapper objectMapper; + + + @Autowired + public UserUtils(RestTemplate restTemplate, ObjectMapper objectMapper) { + this.restTemplate = restTemplate; + this.objectMapper = objectMapper; + } + + + @Cacheable(value = "systemUser", sync = true) + public User fetchSystemUser() { + + UserSearchRequest userSearchRequest = new UserSearchRequest(); + userSearchRequest.setRoleCodes(Collections.singletonList("ANONYMOUS")); + userSearchRequest.setUserType("SYSTEM"); + userSearchRequest.setPageSize(1); + userSearchRequest.setTenantId(stateLevelTenant); + + StringBuilder uri = new StringBuilder(userSearchURI); + User user = null; + try { + UserDetailResponse response = restTemplate.postForObject(uri.toString(), userSearchRequest, UserDetailResponse.class); + if (!CollectionUtils.isEmpty(response.getUser())) + user = response.getUser().get(0); + } catch (Exception e) { + log.error("Exception while fetching system user: ", e); + } + + /*if(user == null) + throw new CustomException("NO_SYSTEUSER_FOUND","No system user found");*/ + + return user; + } + + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/Utils/Utils.java b/core/ifix-zuul/src/main/java/org/egov/Utils/Utils.java new file mode 100644 index 00000000..d6ba56cc --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/Utils/Utils.java @@ -0,0 +1,48 @@ +package org.egov.Utils; + +import com.netflix.zuul.context.RequestContext; +import org.apache.commons.io.IOUtils; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.Optional; + +import static org.egov.constants.RequestContextConstants.*; + +public class Utils { + + private static final String EMPTY_STRING = ""; + private static final String JSON_TYPE = "json"; + + public static String getResponseBody(RequestContext ctx) throws IOException { + String body = ctx.getResponseBody(); + + if (body == null) { + body = IOUtils.toString(ctx.getResponseDataStream()); + ctx.setResponseBody(body); + } + + return body; + } + + public static boolean isRequestBodyCompatible(HttpServletRequest servletRequest) { + return ( + POST.equalsIgnoreCase(getRequestMethod(servletRequest)) + || PUT.equalsIgnoreCase(getRequestMethod(servletRequest)) + || PATCH.equalsIgnoreCase(getRequestMethod(servletRequest)) + ) + && getRequestContentType(servletRequest).contains(JSON_TYPE); + } + + private static String getRequestMethod(HttpServletRequest servletRequest) { + return servletRequest.getMethod(); + } + + private static String getRequestContentType(HttpServletRequest servletRequest) { + return Optional.ofNullable(servletRequest.getContentType()).orElse(EMPTY_STRING).toLowerCase(); + } + + private static String getRequestURI(HttpServletRequest servletRequest) { + return servletRequest.getRequestURI(); + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/ZuulGatewayApplication.java b/core/ifix-zuul/src/main/java/org/egov/ZuulGatewayApplication.java new file mode 100644 index 00000000..84fbae5a --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/ZuulGatewayApplication.java @@ -0,0 +1,104 @@ +package org.egov; + +import com.auth0.jwt.JWTVerifier; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.RateLimitUtils; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.properties.RateLimitProperties; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.support.SecuredRateLimitUtils; +import org.egov.Utils.CustomRateLimitUtils; +import org.egov.Utils.UserUtils; +import org.egov.filters.pre.AuthPreCheckFilter; +import org.egov.filters.pre.JwtAuthenticationFilter; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.cloud.netflix.zuul.EnableZuulProxy; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.PropertySource; +import org.springframework.web.client.RestTemplate; + +import java.util.Arrays; +import java.util.HashSet; + +@EnableZuulProxy +@EnableCaching +@SpringBootApplication +@PropertySource({"${zuul.routes.filepath}", "${zuul.limiter.filepath}"}) +public class ZuulGatewayApplication { + @Value("${egov.user-info-header}") + private String userInfoHeader; + @Value("#{'${egov.open-endpoints-whitelist}'.split(',')}") + private String[] openEndpointsWhitelist; + @Value("#{'${egov.mixed-mode-endpoints-whitelist}'.split(',')}") + private String[] mixedModeEndpointsWhitelist; + @Value("${egov.auth-service-host}") + private String authServiceHost; + @Value("${egov.auth-service-uri}") + private String authServiceUri; + @Value("${egov.authorize.access.control.host}${egov.authorize.access.control.uri}") + private String authorizationUrl; + @Autowired + private RestTemplate restTemplate; + @Autowired + private ObjectMapper objectMapper; + @Autowired + private UserUtils userUtils; + @Autowired + private CustomRateLimitUtils customRateLimitUtils; + + @Autowired + private JWTVerifier jwtVerifier; + + public static void main(String[] args) { + SpringApplication.run(ZuulGatewayApplication.class, args); + } + + @Bean + public JwtAuthenticationFilter keycloakAuthenticationFilter() { + return new JwtAuthenticationFilter(jwtVerifier); + } + + @Bean + public AuthPreCheckFilter authCheckFilter() { + return new AuthPreCheckFilter(new HashSet<>(Arrays.asList(openEndpointsWhitelist)), + new HashSet<>(Arrays.asList(mixedModeEndpointsWhitelist)), userUtils); + } + +// @Bean +// public AuthFilter authFilter() { +// final ProxyRequestHelper proxyRequestHelper = new ProxyRequestHelper(); +// return new AuthFilter(proxyRequestHelper, restTemplate, authServiceHost, authServiceUri); +// } +// +// @Bean +// public RbacFilter rbacFilter() { +// return new RbacFilter(restTemplate, authorizationUrl, objectMapper); +// } +// +// @Bean +// public RbacPreCheckFilter rbacCheckFilter() { +// return new RbacPreCheckFilter(new HashSet<>(Arrays.asList(openEndpointsWhitelist)), +// new HashSet<>(Arrays.asList(mixedModeEndpointsWhitelist)) +// ); +// } + + @Configuration + public static class RateLimitUtilsConfiguration { + + @Bean + @ConditionalOnClass(name = "org.springframework.security.core.Authentication") + public RateLimitUtils securedRateLimitUtils(final RateLimitProperties rateLimitProperties) { + return new SecuredRateLimitUtils(rateLimitProperties); + } + + @Bean + public RateLimitUtils rateLimitUtils(final RateLimitProperties rateLimitProperties) { + return new CustomRateLimitUtils(rateLimitProperties); + } + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/config/Configuration.java b/core/ifix-zuul/src/main/java/org/egov/config/Configuration.java new file mode 100644 index 00000000..4d1798e8 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/config/Configuration.java @@ -0,0 +1,49 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.DefaultRateLimiterErrorHandler; +import com.marcosbarbero.cloud.autoconfigure.zuul.ratelimit.config.repository.RateLimiterErrorHandler; +import org.egov.tracer.model.CustomException; +import org.springframework.context.annotation.Bean; +import org.springframework.http.HttpStatus; +import org.springframework.http.client.BufferingClientHttpRequestFactory; +import org.springframework.http.client.SimpleClientHttpRequestFactory; +import org.springframework.web.client.RestTemplate; + +@org.springframework.context.annotation.Configuration +public class Configuration { + + + @Bean + public RestTemplate restTemplate() { + return new RestTemplate(new BufferingClientHttpRequestFactory(new SimpleClientHttpRequestFactory())); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + } + + @Bean + public RateLimiterErrorHandler rateLimitErrorHandler() { + return new DefaultRateLimiterErrorHandler() { + @Override + public void handleSaveError(String key, Exception e) { + throw new RuntimeException(new CustomException("TOO_MANY_REQUESTS", HttpStatus.TOO_MANY_REQUESTS.toString())); + } + + @Override + public void handleFetchError(String key, Exception e) { + throw new RuntimeException(new CustomException("TOO_MANY_REQUESTS", HttpStatus.TOO_MANY_REQUESTS.toString())); + } + + @Override + public void handleError(String msg, Exception e) { + throw new RuntimeException(new CustomException("TOO_MANY_REQUESTS", HttpStatus.TOO_MANY_REQUESTS.toString())); + } + }; + } + + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/config/KeycloakJwtVerifierConfig.java b/core/ifix-zuul/src/main/java/org/egov/config/KeycloakJwtVerifierConfig.java new file mode 100644 index 00000000..5e0295e3 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/config/KeycloakJwtVerifierConfig.java @@ -0,0 +1,53 @@ +package org.egov.config; + +import com.auth0.jwt.JWT; +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.algorithms.Algorithm; +import com.fasterxml.jackson.databind.JsonNode; +import org.apache.commons.codec.binary.Base64; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.web.client.RestTemplate; + +import java.security.KeyFactory; +import java.security.interfaces.RSAPublicKey; +import java.security.spec.X509EncodedKeySpec; + +@Configuration +public class KeycloakJwtVerifierConfig { + + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + @Value("${keycloak.host}") + private String keycloakHost; + @Value("${keycloak.context-path}") + private String keycloakContextPath; + @Value("${keycloak.realm}") + private String keycloakRealmName; + @Autowired + private RestTemplate restTemplate; + private JWTVerifier jwtVerifier; + + @Bean + public JWTVerifier jwtVerifier() { + String url = keycloakHost + keycloakContextPath + "/realms/" + keycloakRealmName; + JsonNode realmDetails = restTemplate.getForObject(url, JsonNode.class); + String publicKey = realmDetails.get("public_key").asText(); + JWTVerifier jwtVerifier = null; + try { + byte[] encoded = Base64.decodeBase64(publicKey); + KeyFactory kf = KeyFactory.getInstance("RSA"); + RSAPublicKey pubKey = (RSAPublicKey) kf.generatePublic(new X509EncodedKeySpec(encoded)); + + Algorithm algorithm = Algorithm.RSA256(pubKey, null); + jwtVerifier = JWT.require(algorithm).build(); + } catch (Exception e) { + logger.error("Failed to create JWT Verifier"); + } + return jwtVerifier; + } + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/constants/RequestContextConstants.java b/core/ifix-zuul/src/main/java/org/egov/constants/RequestContextConstants.java new file mode 100644 index 00000000..8d4fd83a --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/constants/RequestContextConstants.java @@ -0,0 +1,31 @@ +package org.egov.constants; + +public class RequestContextConstants { + public static final String AUTH_BOOLEAN_FLAG_NAME = "shouldDoAuth"; + public static final String AUTH_TOKEN_KEY = "authToken"; + public static final String JWT_PAYLOAD_KEY = "jwt-payload"; + public static final String ERROR_MESSAGE_KEY = "error.message"; + public static final String ERROR_CODE_KEY = "error.status_code"; + public static final String CURRENT_REQUEST_TENANTID = "request.tenant_id"; + public static final String CURRENT_REQUEST_SANITIZED_BODY = "request.body.sanitized"; + public static final String CURRENT_REQUEST_SANITIZED_BODY_STR = "request.body.sanitized.str"; + public static final String CURRENT_REQUEST_START_TIME = "request.time.start"; + public static final String CURRENT_REQUEST_END_TIME = "request.time.end"; + public static final String GET = "GET"; + public static final String POST = "POST"; + public static final String PUT = "PUT"; + public static final String PATCH = "PATCH"; + + public static final String FILESTORE_REGEX = "^/filestore/.*"; + public static final String REQUEST_HEADER_FIELD_NAME_PASCAL_CASE = "RequestHeader"; + public static final String REQUEST_HEADER_FIELD_NAME_CAMEL_CASE = "requestHeader"; + public static final String USER_INFO_FIELD_NAME = "userInfo"; + public static final String USER_INFO_KEY = "USER_INFO"; + public static final String CORRELATION_ID_FIELD_NAME = "correlationId"; + public static final String CORRELATION_ID_HEADER_NAME = "x-correlation-id"; + public static final String CORRELATION_ID_KEY = "CORRELATION_ID"; + public static final String RBAC_BOOLEAN_FLAG_NAME = "shouldDoRbac"; + public static final String SKIP_RBAC = "RBAC check skipped"; + public static final String REQUEST_TENANT_ID_KEY = "tenantId"; + public static final String TENANT_ID_KEY = "TENANT_ID"; +} diff --git a/core/ifix-zuul/src/main/java/org/egov/contract/Action.java b/core/ifix-zuul/src/main/java/org/egov/contract/Action.java new file mode 100644 index 00000000..d141cc7b --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/contract/Action.java @@ -0,0 +1,37 @@ +package org.egov.contract; + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; + +@JsonIgnoreProperties(ignoreUnknown = true) +public class Action implements java.io.Serializable { + + private static final long serialVersionUID = -6066170463373957428L; + + private static final String OPENING_BRACES = "{"; + private static final String CLOSING_BRACES = "}"; + private static final String PARAMETER_PLACEHOLDER_REGEX = "\\{\\w+\\}"; + private static final String ANY_WORD_REGEX = "\\\\w+"; + + @JsonProperty("url") + private String url; + + public String getUrl() { + return url; + } + + public void setUrl(String url) { + this.url = url; + } + + @JsonIgnore + public boolean hasDynamicFields() { + return url.contains(OPENING_BRACES) & url.contains(CLOSING_BRACES); + } + + @JsonIgnore + public String getRegexUrl() { + return url.replaceAll(PARAMETER_PLACEHOLDER_REGEX, ANY_WORD_REGEX); + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/contract/Role.java b/core/ifix-zuul/src/main/java/org/egov/contract/Role.java new file mode 100644 index 00000000..c76d705f --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/contract/Role.java @@ -0,0 +1,31 @@ +package org.egov.contract; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +@AllArgsConstructor +@NoArgsConstructor +@EqualsAndHashCode(of = {"code", "tenantId"}) +public class Role implements java.io.Serializable { + + private static final long serialVersionUID = 8967926454506815772L; + + @JsonProperty("id") + private Long id; + + @JsonProperty("name") + private String name; + + @JsonProperty("code") + private String code; + + @JsonProperty("tenantId") + private String tenantId; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/contract/User.java b/core/ifix-zuul/src/main/java/org/egov/contract/User.java new file mode 100644 index 00000000..8e94f4e1 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/contract/User.java @@ -0,0 +1,101 @@ +package org.egov.contract; + + +import com.fasterxml.jackson.annotation.JsonIgnore; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +public class User implements java.io.Serializable { + + private static final long serialVersionUID = 3446500028655161135L; + + @JsonProperty("id") + private Integer id; + + @JsonProperty("uuid") + private String uuid; + + @JsonProperty("userName") + private String userName; + + @JsonProperty("name") + private String name; + + @JsonProperty("type") + private String type; + + @JsonProperty("mobileNumber") + private String mobileNumber; + + @JsonProperty("emailId") + private String emailId; + + @JsonProperty("tenantId") + private String tenantId; + + @JsonProperty("roles") + private List roles; + + @JsonIgnore + @JsonProperty("actions") + private List actions; + + public User() { + } + + @JsonIgnore + public List getActions() { + return this.actions; + + } + + public void setActions(List actions) { + this.actions = actions; + } + + public void setId(Integer id) { + this.id = id; + } + + public void setUserName(String userName) { + this.userName = userName; + } + + public void setName(String name) { + this.name = name; + } + + public void setType(String type) { + this.type = type; + } + + public void setMobileNumber(String mobileNumber) { + this.mobileNumber = mobileNumber; + } + + public void setEmailId(String emailId) { + this.emailId = emailId; + } + + public void setRoles(List roles) { + this.roles = roles; + } + + public void setTenantId(String tenantId) { + this.tenantId = tenantId; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/contract/UserInfo.java b/core/ifix-zuul/src/main/java/org/egov/contract/UserInfo.java new file mode 100644 index 00000000..41f7353e --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/contract/UserInfo.java @@ -0,0 +1,35 @@ +package org.egov.contract; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.io.Serializable; +import java.util.List; + +@JsonIgnoreProperties(ignoreUnknown = true) +@Data +@Getter +@Setter +@Builder +@NoArgsConstructor +@AllArgsConstructor +@ToString +@EqualsAndHashCode +public class UserInfo implements Serializable { + + private static final long serialVersionUID = 3446500028655161135L; + + @JsonProperty("uuid") + private String uuid = null; + + @JsonProperty("roles") + private List roles = null; + + @JsonProperty("tenants") + private List tenants = null; + + @JsonProperty("attributes") + private Object attributes = null; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/exceptions/CustomException.java b/core/ifix-zuul/src/main/java/org/egov/exceptions/CustomException.java new file mode 100644 index 00000000..49694cb4 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/exceptions/CustomException.java @@ -0,0 +1,17 @@ +package org.egov.exceptions; + +import com.netflix.zuul.exception.ZuulException; + +public class CustomException extends ZuulException { + public CustomException(Throwable throwable, String sMessage, int nStatusCode, String errorCause) { + super(throwable, sMessage, nStatusCode, errorCause); + } + + public CustomException(String sMessage, int nStatusCode, String errorCause) { + super(sMessage, nStatusCode, errorCause); + } + + public CustomException(Throwable throwable, int nStatusCode, String errorCause) { + super(throwable, nStatusCode, errorCause); + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/error/ErrorFilterFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/error/ErrorFilterFilter.java new file mode 100644 index 00000000..6e078040 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/error/ErrorFilterFilter.java @@ -0,0 +1,34 @@ +package org.egov.filters.error; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.egov.Utils.ExceptionUtils; +import org.springframework.stereotype.Component; + +@Component +public class ErrorFilterFilter extends ZuulFilter { + + private static final String ERROR_STATUS_CODE = "error.status_code"; + + @Override + public String filterType() { + return "error"; + } + + @Override + public int filterOrder() { + return -100; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + RequestContext ctx = RequestContext.getCurrentContext(); + ExceptionUtils.raiseErrorFilterException(ctx); + return null; + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/post/CustomAsyncFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/post/CustomAsyncFilter.java new file mode 100644 index 00000000..111c7a01 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/post/CustomAsyncFilter.java @@ -0,0 +1,106 @@ +//package org.egov.filters.post; +// +//import com.fasterxml.jackson.core.type.TypeReference; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.google.common.io.CharStreams; +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import lombok.extern.slf4j.Slf4j; +//import org.egov.model.CustomAsyncRequest; +//import org.egov.wrapper.CustomRequestWrapper; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.kafka.core.KafkaTemplate; +//import org.springframework.stereotype.Component; +// +//import javax.servlet.http.HttpServletRequest; +//import java.io.IOException; +//import java.io.InputStream; +//import java.io.InputStreamReader; +//import java.util.List; +//import java.util.Map; +// +//@Component +//@Slf4j +//public class CustomAsyncFilter extends ZuulFilter { +// +// @Value("#{'${egov.custom.async.uris}'.split(',')}") +// private List sourceUri; +// +// @Value("${egov.custom.async.filter.topic}") +// private String topic; +// +// @Autowired +// private KafkaTemplate kafkaTemplate; +// +// @Override +// public Object run() { +// log.info("Executing CustomAsyncFilter"); +// RequestContext ctx = RequestContext.getCurrentContext(); +// HttpServletRequest request = ctx.getRequest(); +// try { +// CustomAsyncRequest customAsyncRequest = CustomAsyncRequest.builder().request(jsonToMap(readRequestBody(request))) +// .response(jsonToMap(readResponseBody(ctx))).sourceUri(request.getRequestURI()) +// .queryParamMap(ctx.getRequestQueryParams()).build(); +// log.info("CustomAsyncFilter Topic:" + topic); +// kafkaTemplate.send(topic, customAsyncRequest); +// } catch (Exception ex) { +// log.error("Exception while sending async request to kafka topic: " + ex.getMessage()); +// } +// return null; +// } +// +// @Override +// public boolean shouldFilter() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// String uri = ctx.getRequest().getRequestURI(); +// return sourceUri.contains(uri); +// } +// +// @Override +// public int filterOrder() { +// return 2; +// } +// +// @Override +// public String filterType() { +// return "post"; +// } +// +// private String readResponseBody(RequestContext ctx) { +// String responseBody = null; +// try (final InputStream responseDataStream = ctx.getResponseDataStream()) { +// +// if (responseDataStream != null) +// responseBody = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8")); +// ctx.setResponseBody(responseBody); +// } catch (IOException e) { +// log.error("Error reading body", e); +// } catch (Exception e) { +// log.error("Exception while reading response body: " + e.getMessage()); +// } +// return responseBody; +// } +// +// private Map jsonToMap(String json) { +// Map resMap = null; +// if (json != null) { +// try { +// resMap = new ObjectMapper().readValue(json, new TypeReference>() { +// }); +// } catch (IOException e) { +// // TODO Auto-generated catch block +// log.error("IO exception while converting json to map: " + e.getMessage()); +// } +// } +// return resMap; +// } +// +// private String readRequestBody(HttpServletRequest request) { +// CustomRequestWrapper requestWrapper = new CustomRequestWrapper(request); +// String body = requestWrapper.getPayload(); +// log.info("body:" + body); +// return body; +// } +// +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/post/PostEventLogFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/post/PostEventLogFilter.java new file mode 100644 index 00000000..05587d8b --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/post/PostEventLogFilter.java @@ -0,0 +1,53 @@ +//package org.egov.filters.post; +// +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import com.netflix.zuul.exception.ZuulException; +//import lombok.extern.slf4j.Slf4j; +//import org.egov.Utils.EventLoggerUtil; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.stereotype.Component; +// +//import java.util.List; +// +//@Component +//@Slf4j +//public class PostEventLogFilter extends ZuulFilter { +// +// @Value("${eventlog.enabled:false}") +// Boolean eventLogEnabled; +// +// @Value("${eventlog.topic}") +// String eventLogSuccessTopic; +// +// @Value("#{'${eventlog.urls.whitelist}'.split(',')}") +// private List urlsWhiteList; +// +// @Autowired +// private EventLoggerUtil eventLoggerUtil; +// +// +// @Override +// public String filterType() { +// return "post"; +// } +// +// @Override +// public int filterOrder() { +// return 999; +// } +// +// @Override +// public boolean shouldFilter() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// String requestURL = ctx.getRequest().getRequestURI(); +// Boolean toLog = urlsWhiteList.stream().anyMatch(url -> requestURL.startsWith(url)) || urlsWhiteList.isEmpty(); +// return eventLogEnabled && toLog; +// } +// +// @Override +// public Object run() throws ZuulException { +// return eventLoggerUtil.logCurrentRequest(eventLogSuccessTopic); +// } +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/post/PostHookFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/post/PostHookFilter.java new file mode 100644 index 00000000..4828a2a8 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/post/PostHookFilter.java @@ -0,0 +1,111 @@ +//package org.egov.filters.post; +// +//import com.google.common.io.CharStreams; +//import com.jayway.jsonpath.DocumentContext; +//import com.jayway.jsonpath.JsonPath; +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.commons.io.IOUtils; +//import org.apache.commons.lang.StringUtils; +//import org.egov.UrlProvider; +//import org.egov.Utils.ExceptionUtils; +//import org.egov.model.PostHookFilterRequest; +//import org.egov.tracer.model.CustomException; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.http.HttpStatus; +//import org.springframework.stereotype.Component; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.HttpServerErrorException; +//import org.springframework.web.client.RestTemplate; +// +//import java.io.IOException; +//import java.io.InputStream; +//import java.io.InputStreamReader; +// +//@Component +//@Slf4j +//public class PostHookFilter extends ZuulFilter { +// +// @Autowired +// private RestTemplate restTemplate; +// +// @Value("${custom.filter.posthooks:false}") +// private boolean loadPostHookFilters; +// +// @Override +// public Object run() { +// +// RequestContext ctx = RequestContext.getCurrentContext(); +// String resBody = readResponseBody(ctx); +// if (StringUtils.isEmpty(resBody)) return null; +// +// DocumentContext resDc = JsonPath.parse(resBody); +// DocumentContext reqDc = parseRequest(ctx); +// String uri = ctx.getRequest().getRequestURI(); +// PostHookFilterRequest req = PostHookFilterRequest.builder().Request(reqDc.jsonString()).Response(resDc.jsonString()).build(); +// String response = null; +// try { +// log.debug("Executing post-hook filter. Sending request to - " + UrlProvider.getUrlPostHooksMap().get(uri)); +// response = restTemplate.postForObject(UrlProvider.getUrlPostHooksMap().get(uri), req, +// String.class); +// } catch (HttpClientErrorException | HttpServerErrorException e) { +// log.error("POST-Hook - Http Exception Occurred", e); +// ExceptionUtils.raiseCustomException(e.getStatusCode(), "POST_HOOK_ERROR - Post-hook url threw an error - " + e.getMessage()); +// } catch (Exception e) { +// log.error("POST-Hook - Exception Occurred", e); +// ExceptionUtils.raiseCustomException(HttpStatus.BAD_REQUEST, "POST_HOOK_ERROR - Post-hook url threw an error - " + e.getMessage()); +// } +// +// ctx.setResponseBody(response); +// return null; +// } +// +// @Override +// public boolean shouldFilter() { +// if (!loadPostHookFilters) +// return false; +// +// RequestContext ctx = RequestContext.getCurrentContext(); +// String uri = ctx.getRequest().getRequestURI(); +// return UrlProvider.getUrlPostHooksMap().get(uri) != null; +// } +// +// @Override +// public int filterOrder() { +// return 1; +// } +// +// @Override +// public String filterType() { +// return "post"; +// } +// +// private String readResponseBody(RequestContext ctx) { +// String responseBody = null; +// try (final InputStream responseDataStream = ctx.getResponseDataStream()) { +// responseBody = CharStreams.toString(new InputStreamReader(responseDataStream, "UTF-8")); +// //ctx.setResponseBody(responseBody); +// } catch (IOException e) { +// log.error("Error reading body", e); +// } catch (Exception e) { +// log.error("Exception while reading response body: " + e.getMessage()); +// } +// return responseBody; +// } +// +// private DocumentContext parseRequest(RequestContext ctx) { +// +// String payload = null; +// try { +// InputStream is = ctx.getRequest().getInputStream(); +// payload = IOUtils.toString(is); +// //request.getRequestURI(); +// } catch (IOException e) { +// throw new CustomException("REQUEST_PARSING_ERROR", e.getMessage()); +// } +// return JsonPath.parse(payload); +// } +// +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseEnhancementFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseEnhancementFilter.java new file mode 100644 index 00000000..99c22ca8 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseEnhancementFilter.java @@ -0,0 +1,51 @@ +package org.egov.filters.post; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import static org.egov.constants.RequestContextConstants.CORRELATION_ID_KEY; + +/** + * Sets the correlation id to the response header. + */ +@Component +public class ResponseEnhancementFilter extends ZuulFilter { + + private static final String CORRELATION_HEADER_NAME = "x-correlation-id"; + private static final String RECEIVED_RESPONSE_MESSAGE = "Received response code: {} from upstream URI {}"; + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public String filterType() { + return "post"; + } + + @Override + public int filterOrder() { + return 0; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.addZuulResponseHeader(CORRELATION_HEADER_NAME, getCorrelationId()); + ctx.addZuulResponseHeader("Cache-Control", "no-cache, no-store, max-age=0, must-revalidate"); + + return null; + } + + private String getCorrelationId() { + RequestContext ctx = RequestContext.getCurrentContext(); + logger.info(RECEIVED_RESPONSE_MESSAGE, + ctx.getResponse().getStatus(), ctx.getRequest().getRequestURI()); + return (String) ctx.get(CORRELATION_ID_KEY); + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseErrorFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseErrorFilter.java new file mode 100644 index 00000000..35c1f77a --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/post/ResponseErrorFilter.java @@ -0,0 +1,42 @@ +package org.egov.filters.post; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.egov.Utils.ExceptionUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +/** + * Sets the correlation id to the response header. + */ +@Component +public class ResponseErrorFilter extends ZuulFilter { + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public String filterType() { + return "post"; + } + + @Override + public int filterOrder() { + return -1; + } + + @Override + public boolean shouldFilter() { + return RequestContext.getCurrentContext().containsKey("error.status_code") + || RequestContext.getCurrentContext().getResponseStatusCode() == HttpStatus.NOT_FOUND.value() + || RequestContext.getCurrentContext().getResponseStatusCode() == HttpStatus.BAD_REQUEST.value(); + } + + @Override + public Object run() { + RequestContext ctx = RequestContext.getCurrentContext(); + ExceptionUtils.raiseErrorFilterException(ctx); + return null; + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthFilter.java new file mode 100644 index 00000000..fd1c9132 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthFilter.java @@ -0,0 +1,81 @@ +//package org.egov.filters.pre; +// +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import org.egov.Utils.ExceptionUtils; +//import org.egov.contract.User; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; +//import org.springframework.http.HttpEntity; +//import org.springframework.http.HttpHeaders; +//import org.springframework.http.HttpStatus; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.ResourceAccessException; +//import org.springframework.web.client.RestTemplate; +// +//import static org.egov.constants.RequestContextConstants.*; +// +///** +// * 4th pre filter to get executed. +// * If the auth flag is enabled then the user is retrieved for the given auth token. +// */ +//public class AuthFilter extends ZuulFilter { +// +// private static final String INPUT_STREAM_CONVERSION_FAILED_MESSAGE = "Failed to convert to input stream"; +// private static final String RETRIEVING_USER_FAILED_MESSAGE = "Retrieving user failed"; +// private final ProxyRequestHelper helper; +// private final String authServiceHost; +// private final String authUri; +// private final RestTemplate restTemplate; +// private final Logger logger = LoggerFactory.getLogger(this.getClass()); +// +// +// public AuthFilter(ProxyRequestHelper helper, RestTemplate restTemplate, String authServiceHost, String authUri) { +// this.helper = helper; +// this.restTemplate = restTemplate; +// this.authServiceHost = authServiceHost; +// this.authUri = authUri; +// } +// +// @Override +// public String filterType() { +// return "pre"; +// } +// +// @Override +// public int filterOrder() { +// return 3; +// } +// +// @Override +// public boolean shouldFilter() { +// return false; +// } +// +// @Override +// public Object run() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// String authToken = (String) ctx.get(AUTH_TOKEN_KEY); +// try { +// User user = getUser(authToken, ctx); +// ctx.set(USER_INFO_KEY, user); +// } catch (HttpClientErrorException ex) { +// logger.error(RETRIEVING_USER_FAILED_MESSAGE, ex); +// ExceptionUtils.RaiseException(ex); +// } catch (ResourceAccessException ex) { +// logger.error(RETRIEVING_USER_FAILED_MESSAGE, ex); +// ExceptionUtils.raiseCustomException(HttpStatus.INTERNAL_SERVER_ERROR, "User authentication service is down"); +// } +// return null; +// } +// +// private User getUser(String authToken, RequestContext ctx) { +// String authURL = String.format("%s%s%s", authServiceHost, authUri, authToken); +// final HttpHeaders headers = new HttpHeaders(); +// headers.add(CORRELATION_ID_HEADER_NAME, (String) ctx.get(CORRELATION_ID_KEY)); +// final HttpEntity httpEntity = new HttpEntity<>(null, headers); +// return restTemplate.postForObject(authURL, httpEntity, User.class); +// } +// +//} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthPreCheckFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthPreCheckFilter.java new file mode 100644 index 00000000..a8e3dd63 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/AuthPreCheckFilter.java @@ -0,0 +1,212 @@ +package org.egov.filters.pre; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.egov.Utils.ExceptionUtils; +import org.egov.Utils.UserUtils; +import org.egov.Utils.Utils; +import org.egov.contract.User; +import org.egov.model.RequestBodyInspector; +import org.egov.wrapper.CustomRequestWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.http.HttpStatus; +import org.springframework.util.ObjectUtils; + +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; + +import static org.egov.constants.RequestContextConstants.*; + +/** + * 2nd pre filter to get executed. + * Identifies if the URI is part of open or mixed endpoint list. + * If its not present in the open list then the auth token is retrieved from the request body. + * For a restricted endpoint if auth token is not present then an error response is returned. + */ +public class AuthPreCheckFilter extends ZuulFilter { + private static final String AUTH_TOKEN_RETRIEVE_FAILURE_MESSAGE = "Retrieving of auth token failed"; + private static final String OPEN_ENDPOINT_MESSAGE = "Routing to an open endpoint: {}"; + private static final String AUTH_TOKEN_HEADER_MESSAGE = "Fetching auth-token from header for URI: {}"; + private static final String AUTH_TOKEN_BODY_MESSAGE = "Fetching auth-token from request body for URI: {}"; + private static final String AUTH_TOKEN_HEADER_NAME = "auth-token"; + private static final String RETRIEVED_AUTH_TOKEN_MESSAGE = "Auth-token: {}"; + private static final String ROUTING_TO_ANONYMOUS_ENDPOINT_MESSAGE = "Routing to anonymous endpoint: {}"; + private static final String ROUTING_TO_PROTECTED_ENDPOINT_RESTRICTED_MESSAGE = + "Routing to protected endpoint {} restricted - No auth token"; + private static final String UNAUTHORIZED_USER_MESSAGE = "You are not authorized to access this resource"; + private static final String PROCEED_ROUTING_MESSAGE = "Routing to an endpoint: {} - auth provided"; + private static final String NO_REQUEST_INFO_FIELD_MESSAGE = "No request-info field in request body for: {}"; + private static final String AUTH_TOKEN_REQUEST_BODY_FIELD_NAME = "authToken"; + private static final String FAILED_TO_SERIALIZE_REQUEST_BODY_MESSAGE = "Failed to serialize requestBody"; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private final ObjectMapper objectMapper; + private HashSet openEndpointsWhitelist; + private HashSet mixedModeEndpointsWhitelist; + private UserUtils userUtils; + + + public AuthPreCheckFilter(HashSet openEndpointsWhitelist, + HashSet mixedModeEndpointsWhitelist, + UserUtils userUtils) { + this.openEndpointsWhitelist = openEndpointsWhitelist; + this.mixedModeEndpointsWhitelist = mixedModeEndpointsWhitelist; + this.userUtils = userUtils; + objectMapper = new ObjectMapper(); + } + + @Override + public String filterType() { + return "pre"; + } + + @Override + public int filterOrder() { + return 1; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + String authToken; + if (openEndpointsWhitelist.contains(getRequestURI())) { + setShouldDoAuth(false); + logger.info(OPEN_ENDPOINT_MESSAGE, getRequestURI()); + return null; + } + try { + authToken = getAuthTokenFromRequest(); + } catch (IOException e) { + logger.error(AUTH_TOKEN_RETRIEVE_FAILURE_MESSAGE, e); + ExceptionUtils.RaiseException(e); + return null; + } + + RequestContext.getCurrentContext().set(AUTH_TOKEN_KEY, authToken); + if (authToken == null) { + if (mixedModeEndpointsWhitelist.contains(getRequestURI())) { + logger.info(ROUTING_TO_ANONYMOUS_ENDPOINT_MESSAGE, getRequestURI()); + setShouldDoAuth(false); + setAnonymousUser(); + } else { + logger.info(ROUTING_TO_PROTECTED_ENDPOINT_RESTRICTED_MESSAGE, getRequestURI()); + ExceptionUtils.raiseCustomException(HttpStatus.UNAUTHORIZED, UNAUTHORIZED_USER_MESSAGE); + return null; + } + } else { + logger.info(PROCEED_ROUTING_MESSAGE, getRequestURI()); + setShouldDoAuth(true); + } + return null; + } + + private String getAuthTokenFromRequest() throws IOException { + + String authToken = getAuthTokenFromRequestHeader(); + // header will be preferred for auth body + String authTokenFromBody = null; + + HttpServletRequest req = RequestContext.getCurrentContext().getRequest(); + + if (Utils.isRequestBodyCompatible(req)) { + // if body is json try and extract the token from body + // call this method even if we found authtoken in header + // this is just to make sure the authToken doesn't get leaked + // if it was both in header as well as body + authTokenFromBody = getAuthTokenFromRequestBody(); + } + + if (ObjectUtils.isEmpty(authTokenFromBody)) { + // if token is not there, return whatever we had from header + authTokenFromBody = authToken; + } + + return authTokenFromBody; + } + + private String getAuthTokenFromRequestBody() throws IOException { + if (!Utils.isRequestBodyCompatible(getRequest())) + return null; + + CustomRequestWrapper requestWrapper = new CustomRequestWrapper(getRequest()); + HashMap requestBody = getRequestBody(requestWrapper); + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + @SuppressWarnings("unchecked") + HashMap requestHeader = requestBodyInspector.getRequestHeader(); + if (requestHeader == null) { + logger.info(NO_REQUEST_INFO_FIELD_MESSAGE, getRequestURI()); + return null; + } + String authToken = (String) requestHeader.get(AUTH_TOKEN_REQUEST_BODY_FIELD_NAME); + sanitizeAndSetRequest(requestBodyInspector, requestWrapper); + return authToken; + } + + private HashMap getRequestBody(CustomRequestWrapper requestWrapper) throws IOException { + return objectMapper.readValue(requestWrapper.getPayload(), + new TypeReference>() { + }); + } + + private void sanitizeAndSetRequest(RequestBodyInspector requestBodyInspector, CustomRequestWrapper requestWrapper) { + HashMap requestHeader = requestBodyInspector.getRequestHeader(); + RequestContext ctx = RequestContext.getCurrentContext(); + requestHeader.remove(USER_INFO_FIELD_NAME); + requestHeader.remove(AUTH_TOKEN_REQUEST_BODY_FIELD_NAME); + requestBodyInspector.updateRequestHeader(requestHeader); + try { + String requestSanitizedBody = objectMapper.writeValueAsString(requestBodyInspector.getRequestBody()); + ctx.set(CURRENT_REQUEST_SANITIZED_BODY, requestBodyInspector.getRequestBody()); + ctx.set(CURRENT_REQUEST_SANITIZED_BODY_STR, requestSanitizedBody); + requestWrapper.setPayload(requestSanitizedBody); + } catch (JsonProcessingException e) { + logger.error(FAILED_TO_SERIALIZE_REQUEST_BODY_MESSAGE, e); + ExceptionUtils.RaiseException(e); + } + ctx.setRequest(requestWrapper); + } + + private String getAuthTokenFromRequestHeader() { + RequestContext ctx = RequestContext.getCurrentContext(); + try { + return ctx.getRequest().getHeader("Authorization").split(" ")[1]; // To remove "Bearer " + } catch (Exception ex) { + return null; + } + } + + private void setShouldDoAuth(boolean enableAuth) { + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.set(AUTH_BOOLEAN_FLAG_NAME, enableAuth); + } + + private String getRequestURI() { + return getRequest().getRequestURI(); + } + + private HttpServletRequest getRequest() { + RequestContext ctx = RequestContext.getCurrentContext(); + return ctx.getRequest(); + } + + private String getRequestMethod() { + return getRequest().getMethod(); + } + + private void setAnonymousUser() { + User systemUser = userUtils.fetchSystemUser(); + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.set(USER_INFO_KEY, systemUser); + ; + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/CorrelationIdFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/CorrelationIdFilter.java new file mode 100644 index 00000000..a8af7626 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/CorrelationIdFilter.java @@ -0,0 +1,50 @@ +package org.egov.filters.pre; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.slf4j.MDC; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +import static org.egov.constants.RequestContextConstants.CORRELATION_ID_KEY; + +/** + * 1st pre filter to get executed. + * Sets the context and MDC with the newly generated correlation id. + */ +@Component +public class CorrelationIdFilter extends ZuulFilter { + + private static final String RECEIVED_REQUEST_MESSAGE = "Received request for: {}"; + + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + @Override + public String filterType() { + return "pre"; + } + + @Override + public int filterOrder() { + return 0; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + RequestContext ctx = RequestContext.getCurrentContext(); + final String correlationId = UUID.randomUUID().toString(); + MDC.put(CORRELATION_ID_KEY, correlationId); + ctx.set(CORRELATION_ID_KEY, correlationId); + logger.debug(RECEIVED_REQUEST_MESSAGE, ctx.getRequest().getRequestURI()); + return null; + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/JwtAuthenticationFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/JwtAuthenticationFilter.java new file mode 100644 index 00000000..e05c42bb --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/JwtAuthenticationFilter.java @@ -0,0 +1,72 @@ +package org.egov.filters.pre; + +import com.auth0.jwt.JWTVerifier; +import com.auth0.jwt.interfaces.DecodedJWT; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import lombok.SneakyThrows; +import org.apache.commons.codec.binary.Base64; +import org.apache.commons.codec.binary.StringUtils; +import org.egov.Utils.ExceptionUtils; +import org.egov.Utils.JwtUtil; +import org.egov.contract.UserInfo; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.stereotype.Component; + +import static org.egov.constants.RequestContextConstants.*; + +@Component +public class JwtAuthenticationFilter extends ZuulFilter { + + private static final String INVALID_JWT = "Invalid JWT"; + private final Logger logger = LoggerFactory.getLogger(this.getClass()); + private JWTVerifier jwtVerifier; + + @Autowired + private JwtUtil jwtUtil; + + public JwtAuthenticationFilter(JWTVerifier jwtVerifier) { + this.jwtVerifier = jwtVerifier; + } + + @Override + public String filterType() { + return "pre"; + } + + @Override + public int filterOrder() { + return 3; + } + + @Override + public boolean shouldFilter() { + return RequestContext.getCurrentContext().getBoolean(AUTH_BOOLEAN_FLAG_NAME); + } + + @SneakyThrows + @Override + public Object run() throws ZuulException { + RequestContext context = RequestContext.getCurrentContext(); + String authToken = (String) context.get(AUTH_TOKEN_KEY); + DecodedJWT decodedJWT = null; + + try { + decodedJWT = jwtVerifier.verify(authToken); + } catch (Exception ex) { + logger.error(INVALID_JWT, ex); + ExceptionUtils.raiseCustomException(HttpStatus.UNAUTHORIZED, "Verifying JWT failed"); + } + + String payload = StringUtils.newStringUtf8(Base64.decodeBase64(decodedJWT.getPayload())); + context.set(JWT_PAYLOAD_KEY, payload); + UserInfo userInfo = jwtUtil.createUserInfoFromJwt(payload); + context.set(USER_INFO_KEY, userInfo); + return null; + } + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/PreHookFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/PreHookFilter.java new file mode 100644 index 00000000..0814e4b5 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/PreHookFilter.java @@ -0,0 +1,96 @@ +//package org.egov.filters.pre; +// +//import com.jayway.jsonpath.DocumentContext; +//import com.jayway.jsonpath.JsonPath; +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import lombok.extern.slf4j.Slf4j; +//import org.apache.commons.io.IOUtils; +//import org.egov.UrlProvider; +//import org.egov.Utils.ExceptionUtils; +//import org.egov.model.PreHookFilterRequest; +//import org.egov.tracer.model.CustomException; +//import org.egov.wrapper.CustomRequestWrapper; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.beans.factory.annotation.Value; +//import org.springframework.http.HttpStatus; +//import org.springframework.stereotype.Component; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.HttpServerErrorException; +//import org.springframework.web.client.RestTemplate; +// +//import java.io.IOException; +//import java.io.InputStream; +// +//@Component +//@Slf4j +//public class PreHookFilter extends ZuulFilter { +// +// @Autowired +// private RestTemplate restTemplate; +// +// @Value("${custom.filter.prehooks:false}") +// private boolean loadPreHookFilters; +// +// @Override +// public Object run() { +// +// RequestContext ctx = RequestContext.getCurrentContext(); +// +// DocumentContext reqDc = parseRequest(ctx); +// String uri = ctx.getRequest().getRequestURI(); +// PreHookFilterRequest req = PreHookFilterRequest.builder().Request(reqDc.jsonString()).build(); +// String response = null; +// try { +// log.debug("Executing pre-hook filter. Sending request to - " + UrlProvider.getUrlPreHooksMap().get(uri)); +// response = restTemplate.postForObject(UrlProvider.getUrlPreHooksMap().get(uri), req, +// String.class); +// +// CustomRequestWrapper requestWrapper = new CustomRequestWrapper(ctx.getRequest()); +// requestWrapper.setPayload(response); +// ctx.setRequest(requestWrapper); +// } catch (HttpClientErrorException | HttpServerErrorException e) { +// log.error("Pre-Hook - Http Exception Occurred", e); +// ExceptionUtils.raiseCustomException(e.getStatusCode(), "PRE_HOOK_ERROR - Pre-hook url threw an error - " + e.getMessage()); +// } catch (Exception e) { +// log.error("Pre-Hook - Exception Occurred", e); +// ExceptionUtils.raiseCustomException(HttpStatus.BAD_REQUEST, "PRE_HOOK_ERROR - Pre-hook url threw an error - " + e.getMessage()); +// } +// +// return null; +// } +// +// @Override +// public boolean shouldFilter() { +// if (!loadPreHookFilters) +// return false; +// +// RequestContext ctx = RequestContext.getCurrentContext(); +// String uri = ctx.getRequest().getRequestURI(); +// return UrlProvider.getUrlPreHooksMap().get(uri) != null; +// } +// +// @Override +// public int filterOrder() { +// return 1; +// } +// +// @Override +// public String filterType() { +// return "pre"; +// } +// +// private DocumentContext parseRequest(RequestContext ctx) { +// +// String payload = null; +// try { +// InputStream is = ctx.getRequest().getInputStream(); +// payload = IOUtils.toString(is); +// //request.getRequestURI(); +// } catch (IOException e) { +// throw new CustomException("REQUEST_PARSING_ERROR", e.getMessage()); +// } +// return JsonPath.parse(payload); +// } +// +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacFilter.java new file mode 100644 index 00000000..24f8c823 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacFilter.java @@ -0,0 +1,191 @@ +//package org.egov.filters.pre; +// +//import com.fasterxml.jackson.databind.JsonNode; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.fasterxml.jackson.databind.node.JsonNodeType; +//import com.fasterxml.jackson.databind.node.ObjectNode; +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import lombok.extern.slf4j.Slf4j; +//import org.egov.Utils.ExceptionUtils; +//import org.egov.Utils.Utils; +//import org.egov.common.contract.request.RequestHeader; +//import org.egov.contract.User; +//import org.egov.exceptions.CustomException; +//import org.egov.model.AuthorizationRequest; +//import org.egov.model.AuthorizationRequestWrapper; +//import org.springframework.beans.factory.annotation.Autowired; +//import org.springframework.http.HttpStatus; +//import org.springframework.http.ResponseEntity; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.RestTemplate; +// +//import javax.servlet.http.HttpServletRequest; +//import java.io.IOException; +//import java.util.*; +// +//import static java.util.Objects.isNull; +//import static org.egov.constants.RequestContextConstants.*; +// +///** +// * 5th pre filter to get executed. +// * Filter gets executed if the RBAC flag is enabled. Returns an error if the URI is not present in the authorized action list. +// */ +//@Slf4j +//public class RbacFilter extends ZuulFilter { +// +// private static final String FORBIDDEN_MESSAGE = "Not authorized to access this resource"; +// +// private RestTemplate restTemplate; +// +// private String authorizationUrl; +// +// private ObjectMapper objectMapper; +// +// +// @Autowired +// public RbacFilter(RestTemplate restTemplate, String authorizationUrl, ObjectMapper objectMapper) { +// this.restTemplate = restTemplate; +// this.authorizationUrl = authorizationUrl; +// this.objectMapper = objectMapper; +// } +// +// @Override +// public String filterType() { +// return "pre"; +// } +// +// @Override +// public int filterOrder() { +// return 4; +// } +// +// @Override +// public boolean shouldFilter() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// return ctx.getBoolean(RBAC_BOOLEAN_FLAG_NAME); +// } +// +// @Override +// public Object run() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// final boolean isIncomingURIInAuthorizedActionList = isIncomingURIInAuthorizedActionList(ctx); +// if (isIncomingURIInAuthorizedActionList) +// return null; +// +// ExceptionUtils.raiseCustomException(HttpStatus.FORBIDDEN, FORBIDDEN_MESSAGE); +// return null; +// } +// +// private boolean isIncomingURIInAuthorizedActionList(RequestContext ctx) { +// String requestUri = ctx.getRequest().getRequestURI(); +// User user = (User) ctx.get(USER_INFO_KEY); +// +// if (user == null) { +// ExceptionUtils.raiseCustomException(HttpStatus.UNAUTHORIZED, "User information not found. Can't execute RBAC filter"); +// } +// +// Set tenantId = validateRequestAndSetRequestTenantId(); +// +// ctx.set(CURRENT_REQUEST_TENANTID, String.join(",", tenantId)); +// +// AuthorizationRequest request = AuthorizationRequest.builder() +// .roles(new HashSet<>(user.getRoles())) +// .uri(requestUri) +// .tenantIds(tenantId) +// .build(); +// +// return isUriAuthorized(request); +// +// } +// +// private Set validateRequestAndSetRequestTenantId() { +// +// RequestContext ctx = RequestContext.getCurrentContext(); +// +// return getTenantIdForRequest(ctx); +// } +// +// private Set getTenantIdForRequest(RequestContext ctx) { +// HttpServletRequest request = ctx.getRequest(); +// Map> queryParams = ctx.getRequestQueryParams(); +// +// Set tenantIds = new HashSet<>(); +// +// +// if (Utils.isRequestBodyCompatible(request)) { +// +// try { +// ObjectNode requestBody = (ObjectNode) objectMapper.readTree(request.getInputStream()); +// +// stripRequestHeader(requestBody); +// +// List tenants = new LinkedList<>(); +// +// for (JsonNode node : requestBody.findValues(REQUEST_TENANT_ID_KEY)) { +// if (node.getNodeType() == JsonNodeType.ARRAY) { +// node.elements().forEachRemaining(n -> tenants.add(n.asText())); +// } else if (node.getNodeType() == JsonNodeType.STRING) { +// tenants.add(node.asText()); +// } +// } +// if (!tenants.isEmpty()) +// // Filtering null tenantids will be removed once fix is done in TL service. +// tenants.forEach(tenant -> { +// if (tenant != null && !tenant.equalsIgnoreCase("null")) +// tenantIds.add(tenant); +// }); +// else { +// if (!isNull(queryParams) && queryParams.containsKey(REQUEST_TENANT_ID_KEY) && !queryParams.get(REQUEST_TENANT_ID_KEY).isEmpty()) { +// String tenantId = queryParams.get(REQUEST_TENANT_ID_KEY).get(0); +// if (tenantId.contains(",")) { +// tenantIds.addAll(Arrays.asList(tenantId.split(","))); +// } else +// tenantIds.add(tenantId); +// +// } +// } +// +// } catch (IOException e) { +// throw new RuntimeException(new CustomException("REQUEST_PARSE_FAILED", HttpStatus.UNAUTHORIZED.value(), "Failed to parse request at" + +// " API gateway")); +// } +// } +// +// if (tenantIds.isEmpty()) { +// tenantIds.add(((User) ctx.get(USER_INFO_KEY)).getTenantId()); +// } +// +// return tenantIds; +// } +// +// private void stripRequestHeader(ObjectNode requestBody) { +// if (requestBody.has(REQUEST_INFO_FIELD_NAME_PASCAL_CASE)) +// requestBody.remove(REQUEST_INFO_FIELD_NAME_PASCAL_CASE); +// +// else if (requestBody.has(REQUEST_INFO_FIELD_NAME_CAMEL_CASE)) +// requestBody.remove(REQUEST_INFO_FIELD_NAME_CAMEL_CASE); +// +// } +// +// private boolean isUriAuthorized(AuthorizationRequest authorizationRequest) { +// AuthorizationRequestWrapper authorizationRequestWrapper = new AuthorizationRequestWrapper(new RequestHeader(), +// authorizationRequest); +// +// try { +// ResponseEntity responseEntity = restTemplate.postForEntity(authorizationUrl, authorizationRequestWrapper, Void +// .class); +// +// return responseEntity.getStatusCode().equals(HttpStatus.OK); +// } catch (HttpClientErrorException e) { +// log.warn("Exception while attempting to authorize via access control", e); +// return false; +// } catch (Exception e) { +// log.error("Unknown exception occurred while attempting to authorize via access control", e); +// return false; +// } +// +// } +// +// +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacPreCheckFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacPreCheckFilter.java new file mode 100644 index 00000000..b25be25e --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RbacPreCheckFilter.java @@ -0,0 +1,67 @@ +//package org.egov.filters.pre; +// +//import com.netflix.zuul.ZuulFilter; +//import com.netflix.zuul.context.RequestContext; +//import org.slf4j.Logger; +//import org.slf4j.LoggerFactory; +//import org.springframework.beans.factory.annotation.Autowired; +// +//import java.util.HashSet; +// +//import static org.egov.constants.RequestContextConstants.RBAC_BOOLEAN_FLAG_NAME; +//import static org.egov.constants.RequestContextConstants.SKIP_RBAC; +// +///** +// * 3rd pre filter to get executed. +// * If the URI is part of open or mixed endpoint list then RBAC check is marked as false +// */ +//public class RbacPreCheckFilter extends ZuulFilter { +// +// private final Logger logger = LoggerFactory.getLogger(this.getClass()); +// private HashSet openEndpointsWhitelist; +// private HashSet anonymousEndpointsWhitelist; +// +// @Autowired +// public RbacPreCheckFilter(HashSet openEndpointsWhitelist, +// HashSet anonymousEndpointsWhitelist) { +// this.openEndpointsWhitelist = openEndpointsWhitelist; +// this.anonymousEndpointsWhitelist = anonymousEndpointsWhitelist; +// } +// +// @Override +// public String filterType() { +// return "pre"; +// } +// +// @Override +// public int filterOrder() { +// return 2; +// } +// +// @Override +// public boolean shouldFilter() { +// return true; +// } +// +// @Override +// public Object run() { +// if ((openEndpointsWhitelist.contains(getRequestURI()) +// || anonymousEndpointsWhitelist.contains(getRequestURI()))) { +// setShouldDoRbac(false); +// logger.info(SKIP_RBAC, getRequestURI()); +// return null; +// } +// setShouldDoRbac(true); +// return null; +// } +// +// private void setShouldDoRbac(boolean enableRbac) { +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(RBAC_BOOLEAN_FLAG_NAME, enableRbac); +// } +// +// private String getRequestURI() { +// return RequestContext.getCurrentContext().getRequest().getRequestURI(); +// } +// +//} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestEnrichmentFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestEnrichmentFilter.java new file mode 100644 index 00000000..aaf231de --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestEnrichmentFilter.java @@ -0,0 +1,170 @@ +package org.egov.filters.pre; + +import com.fasterxml.jackson.core.JsonGenerator; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import org.apache.commons.io.IOUtils; +import org.egov.Utils.ExceptionUtils; +import org.egov.contract.User; +import org.egov.contract.UserInfo; +import org.egov.model.RequestBodyInspector; +import org.egov.tracer.model.CustomException; +import org.egov.wrapper.CustomRequestWrapper; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + +import java.io.IOException; +import java.util.HashMap; + +import static org.egov.Utils.Utils.isRequestBodyCompatible; +import static org.egov.constants.RequestContextConstants.*; + +/** + * 6th pre filter to get executed. + * Enriches the request body and header with 1) correlation id 2) user info + */ +@Component +public class RequestEnrichmentFilter extends ZuulFilter { + + private static final String FAILED_TO_ENRICH_REQUEST_BODY_MESSAGE = "Failed to enrich request body"; + private static final String USER_SERIALIZATION_MESSAGE = "Failed to serialize user"; + private static final String SKIPPED_BODY_ENRICHMENT_DUE_TO_NO_KNOWN_FIELD_MESSAGE = + "Skipped enriching request body since request info field is not present."; + private static final String BODY_ENRICHED_MESSAGE = "Enriched request payload."; + private static final String ADDED_USER_INFO_TO_HEADER_MESSAGE = "Adding user info to header."; + private static final String EMPTY_STRING = ""; + private static final String JSON_TYPE = "json"; + private static final String USER_INFO_HEADER_NAME = "x-user-info"; + private static final String PASS_THROUGH_GATEWAY_HEADER_NAME = "x-pass-through-gateway"; + private static final String PASS_THROUGH_GATEWAY_HEADER_VALUE = "true"; + private final ObjectMapper objectMapper; + private Logger logger = LoggerFactory.getLogger(this.getClass()); + + public RequestEnrichmentFilter() { + this.objectMapper = new ObjectMapper(); + objectMapper.getFactory().configure(JsonGenerator.Feature.ESCAPE_NON_ASCII, true); + + } + + @Override + public String filterType() { + return "pre"; + } + + @Override + public int filterOrder() { + return 5; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() { + modifyRequestBody(); + addRequestHeaders(); + return null; + } + + private void addRequestHeaders() { + RequestContext ctx = RequestContext.getCurrentContext(); + addCorrelationIdHeader(ctx); + addUserInfoHeader(ctx); + addPassThroughGatewayHeader(ctx); + } + + private void addUserInfoHeader(RequestContext ctx) { + if (isUserInfoPresent() && !isRequestBodyCompatible(ctx.getRequest())) { + UserInfo user = getUser(); + try { + ctx.addZuulRequestHeader(USER_INFO_HEADER_NAME, objectMapper.writeValueAsString(user)); + logger.info(ADDED_USER_INFO_TO_HEADER_MESSAGE); + } catch (JsonProcessingException e) { + logger.error(USER_SERIALIZATION_MESSAGE, e); + ExceptionUtils.RaiseException(e); + } + + } + } + + private void addCorrelationIdHeader(RequestContext ctx) { + ctx.addZuulRequestHeader(CORRELATION_ID_HEADER_NAME, getCorrelationId()); + } + + private void addPassThroughGatewayHeader(RequestContext ctx) { + ctx.addZuulRequestHeader(PASS_THROUGH_GATEWAY_HEADER_NAME, PASS_THROUGH_GATEWAY_HEADER_VALUE); + } + + private void modifyRequestBody() { + if (!isRequestBodyCompatible(RequestContext.getCurrentContext().getRequest())) { + return; + } + try { + enrichRequestBody(); + } catch (IOException e) { + logger.error(FAILED_TO_ENRICH_REQUEST_BODY_MESSAGE, e); + throw new CustomException("FAILED_TO_ENRICH_REQUEST_BODY", e.getMessage()); + } + } + + @SuppressWarnings("unchecked") + private void enrichRequestBody() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + final RequestBodyInspector requestBodyInspector = getRequestBodyInspector(ctx); + HashMap requestHeader = requestBodyInspector.getRequestHeader(); + if (requestHeader == null) { + logger.info(SKIPPED_BODY_ENRICHMENT_DUE_TO_NO_KNOWN_FIELD_MESSAGE); + return; + } + setUserInfo(requestHeader); + setCorrelationId(requestHeader); + requestBodyInspector.updateRequestHeader(requestHeader); + CustomRequestWrapper requestWrapper = new CustomRequestWrapper(ctx.getRequest()); + requestWrapper.setPayload(objectMapper.writeValueAsString(requestBodyInspector.getRequestBody())); + logger.info(BODY_ENRICHED_MESSAGE); + ctx.setRequest(requestWrapper); + } + + private RequestBodyInspector getRequestBodyInspector(RequestContext ctx) throws IOException { + HashMap requestBody = getRequestBody(ctx); + return new RequestBodyInspector(requestBody); + } + + private String getCorrelationId() { + RequestContext ctx = RequestContext.getCurrentContext(); + return (String) ctx.get(CORRELATION_ID_KEY); + } + + private void setCorrelationId(HashMap requestHeader) { + requestHeader.put(CORRELATION_ID_FIELD_NAME, getCorrelationId()); + } + + private void setUserInfo(HashMap requestheader) { + if (isUserInfoPresent()) { + requestheader.put(USER_INFO_FIELD_NAME, getUser()); + } + } + + private UserInfo getUser() { + RequestContext ctx = RequestContext.getCurrentContext(); + return (UserInfo) ctx.get(USER_INFO_KEY); + } + + private boolean isUserInfoPresent() { + RequestContext ctx = RequestContext.getCurrentContext(); + return ctx.get(USER_INFO_KEY) != null; + } + + private HashMap getRequestBody(RequestContext ctx) throws IOException { + String payload = IOUtils.toString(ctx.getRequest().getInputStream()); + return objectMapper.readValue(payload, new TypeReference>() { + }); + } + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestStartTimeFilter.java b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestStartTimeFilter.java new file mode 100644 index 00000000..ef9d76b5 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/filters/pre/RequestStartTimeFilter.java @@ -0,0 +1,32 @@ +package org.egov.filters.pre; + +import com.netflix.zuul.ZuulFilter; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.exception.ZuulException; +import org.egov.constants.RequestContextConstants; +import org.springframework.stereotype.Component; + +@Component +public class RequestStartTimeFilter extends ZuulFilter { + @Override + public String filterType() { + return "pre"; + } + + @Override + public int filterOrder() { + return -999; + } + + @Override + public boolean shouldFilter() { + return true; + } + + @Override + public Object run() throws ZuulException { + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.set(RequestContextConstants.CURRENT_REQUEST_START_TIME, System.currentTimeMillis()); + return null; + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/kafka/HashMapDeserializer.java b/core/ifix-zuul/src/main/java/org/egov/kafka/HashMapDeserializer.java new file mode 100644 index 00000000..1e0e6376 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/kafka/HashMapDeserializer.java @@ -0,0 +1,16 @@ +package org.egov.kafka; + +import org.springframework.kafka.support.serializer.JsonDeserializer; + +import java.util.HashMap; + +public class HashMapDeserializer extends JsonDeserializer { + + public HashMapDeserializer() { + super(HashMap.class); + } + + +} + + diff --git a/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequest.java new file mode 100644 index 00000000..a8e37cdb --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequest.java @@ -0,0 +1,29 @@ +package org.egov.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.contract.Role; + +import javax.validation.constraints.NotNull; +import javax.validation.constraints.Size; +import java.util.Set; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class AuthorizationRequest { + + @NotNull + @Size(min = 1) + private Set roles; + + @NotNull + private String uri; + + @NotNull + private Set tenantIds; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequestWrapper.java b/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequestWrapper.java new file mode 100644 index 00000000..05d3f51b --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/AuthorizationRequestWrapper.java @@ -0,0 +1,22 @@ +package org.egov.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.common.contract.request.RequestHeader; + +@NoArgsConstructor +@AllArgsConstructor +@Data +@Builder +public class AuthorizationRequestWrapper { + + @JsonProperty("requestHeader") + private RequestHeader requestHeader; + + @JsonProperty("AuthorizationRequest") + private AuthorizationRequest authorizationRequest; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/CustomAsyncRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/CustomAsyncRequest.java new file mode 100644 index 00000000..950207d1 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/CustomAsyncRequest.java @@ -0,0 +1,25 @@ +package org.egov.model; + +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import lombok.extern.slf4j.Slf4j; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Setter +@Getter +@ToString +@Slf4j +@Builder +public class CustomAsyncRequest { + + Map> queryParamMap = new HashMap<>(); + private Map request; + private Map response; + private String sourceUri; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/EventLogRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/EventLogRequest.java new file mode 100644 index 00000000..bd422ff4 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/EventLogRequest.java @@ -0,0 +1,144 @@ +package org.egov.model; + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.netflix.zuul.context.RequestContext; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.io.IOUtils; +import org.egov.Utils.Utils; +import org.egov.contract.User; + +import java.io.IOException; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.HashMap; +import java.util.Locale; +import java.util.TimeZone; + +import static org.egov.constants.RequestContextConstants.*; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +@Slf4j +public class EventLogRequest { + private static final ObjectMapper objectMapper = new ObjectMapper(); + + Object requestBody; + + Object responseBody; + + String method; + String referer; + String url; + String responseContentType; + String queryParams; + Integer uid; + String username; + + int statusCode; + + String timestamp; + String userType; + Long requestDuration; + + String correlationId; + String userTenantId; + String userId; + + String tenantId; + + private static Boolean isJsonResponse(RequestContext ctx) { + return ctx.getZuulResponseHeaders().stream().anyMatch(p -> { + if (p.first().toLowerCase().startsWith("content-type") + && p.second().toLowerCase().startsWith("application/json")) + return true; + return false; + }); + } + + public static EventLogRequest fromRequestContext(RequestContext ctx, RequestCaptureCriteria criteria) { + Object body = null; + if (criteria.isCaptureInputBody()) { + body = ctx.get(CURRENT_REQUEST_SANITIZED_BODY_STR); + + if (body == null) { + try { + body = IOUtils.toString(ctx.getRequest().getInputStream()); + } catch (IOException e) { + log.error("Exception while converting input stream to string: " + e.getMessage()); + } + } + } + + String referer = ctx.getRequest().getHeader("referer"); + String method = ctx.getRequest().getMethod(); + Long startTime = (Long) ctx.get(CURRENT_REQUEST_START_TIME); + Long endTime = System.currentTimeMillis(); + ctx.set(CURRENT_REQUEST_END_TIME, endTime); + + Object responseBody = null; + boolean isErrorStatusCode = !(ctx.getResponseStatusCode() >= 200 && ctx.getResponseStatusCode() < 300); + if ( + criteria.isCaptureOutputBody() || + (criteria.isCaptureOutputBodyOnlyForError() && isErrorStatusCode) + ) { + try { + responseBody = Utils.getResponseBody(ctx); + if (isJsonResponse(ctx)) { + responseBody = objectMapper.readValue((String) responseBody, + new TypeReference>() { + }); + } + } catch (Exception e) { + log.error("Exception while reading body", e); + } + } + + + User user = (User) ctx.get(USER_INFO_KEY); + + String uuid = ""; + String userType = ""; + String userTenantId = ""; + String userName = ""; + Integer userId = 0; + + if (user != null) { + uuid = user.getUuid(); + userType = user.getType(); + userTenantId = user.getTenantId(); + userName = user.getUserName(); + userId = user.getId(); + } + + SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US); + Date date = new Date(startTime); + formatter.setTimeZone(TimeZone.getTimeZone("UTC")); + + EventLogRequest req = EventLogRequest.builder() + .requestBody(body) + .method(method) + .referer(referer) + .username(userName) + .uid(userId) + .userType(userType) + .responseBody(responseBody) + .queryParams(ctx.getRequest().getQueryString()) + .correlationId((String) ctx.get(CORRELATION_ID_KEY)) + .statusCode(ctx.getResponseStatusCode()) + .timestamp(formatter.format(date)) + .requestDuration(endTime - startTime) + .userId(uuid) + .userTenantId(userTenantId) + .tenantId((String) ctx.get(CURRENT_REQUEST_TENANTID)) + .url(ctx.getRequest().getRequestURI()).build(); + + return req; + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/PostHookFilterRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/PostHookFilterRequest.java new file mode 100644 index 00000000..211b6511 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/PostHookFilterRequest.java @@ -0,0 +1,18 @@ +package org.egov.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PostHookFilterRequest { + + private String Request; + + private String Response; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/PreHookFilterRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/PreHookFilterRequest.java new file mode 100644 index 00000000..b369514c --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/PreHookFilterRequest.java @@ -0,0 +1,16 @@ +package org.egov.model; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Builder +@Data +@NoArgsConstructor +@AllArgsConstructor +public class PreHookFilterRequest { + + private String Request; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/RequestBodyInspector.java b/core/ifix-zuul/src/main/java/org/egov/model/RequestBodyInspector.java new file mode 100644 index 00000000..a9fcfb52 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/RequestBodyInspector.java @@ -0,0 +1,58 @@ +package org.egov.model; + +import java.util.HashMap; + +import static org.egov.constants.RequestContextConstants.REQUEST_HEADER_FIELD_NAME_CAMEL_CASE; +import static org.egov.constants.RequestContextConstants.REQUEST_HEADER_FIELD_NAME_PASCAL_CASE; + +public class RequestBodyInspector { + private HashMap requestBody; + + public RequestBodyInspector(HashMap requestBody) { + this.requestBody = requestBody; + } + + public boolean isRequestHeaderPresent() { + return requestBody != null && isRequestHeaderContainerFieldPresent(); + } + + public HashMap getRequestBody() { + return requestBody; + } + + public void updateRequestHeader(HashMap requestHeader) { + if (!isRequestHeaderPresent()) { + return; + } + requestBody.put(getRequestHeaderFieldNamePresent(), requestHeader); + } + + @SuppressWarnings("unchecked") + public HashMap getRequestHeader() { + if (isRequestHeaderPresent()) { + return (HashMap) requestBody.get(getRequestHeaderFieldNamePresent()); + } + return null; + } + + private String getRequestHeaderFieldNamePresent() { + if (isPascalCasePresent()) { + return REQUEST_HEADER_FIELD_NAME_PASCAL_CASE; + } else { + return REQUEST_HEADER_FIELD_NAME_CAMEL_CASE; + } + } + + private boolean isRequestHeaderContainerFieldPresent() { + return isPascalCasePresent() || isCamelCasePresent(); + } + + private boolean isCamelCasePresent() { + return requestBody.containsKey(REQUEST_HEADER_FIELD_NAME_CAMEL_CASE); + } + + private boolean isPascalCasePresent() { + return requestBody.containsKey(REQUEST_HEADER_FIELD_NAME_PASCAL_CASE); + } + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/RequestCaptureCriteria.java b/core/ifix-zuul/src/main/java/org/egov/model/RequestCaptureCriteria.java new file mode 100644 index 00000000..b4f16ef8 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/RequestCaptureCriteria.java @@ -0,0 +1,16 @@ +package org.egov.model; + +import lombok.*; + +@Builder +@Data +@AllArgsConstructor +@NoArgsConstructor +@Getter +@Setter +public class RequestCaptureCriteria { + boolean captureInputBody; + boolean captureOutputBody; + boolean captureOutputBodyOnlyForError; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/UserDetailResponse.java b/core/ifix-zuul/src/main/java/org/egov/model/UserDetailResponse.java new file mode 100644 index 00000000..8a38cccc --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/UserDetailResponse.java @@ -0,0 +1,23 @@ +package org.egov.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.contract.User; + +import java.util.List; + +@AllArgsConstructor +@NoArgsConstructor +@Getter +public class UserDetailResponse { + + @JsonProperty("responseheader") + ResponseHeader responseHeader; + + @JsonProperty("user") + List user; + +} diff --git a/core/ifix-zuul/src/main/java/org/egov/model/UserSearchRequest.java b/core/ifix-zuul/src/main/java/org/egov/model/UserSearchRequest.java new file mode 100644 index 00000000..905a74ae --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/model/UserSearchRequest.java @@ -0,0 +1,50 @@ +package org.egov.model; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Getter; +import lombok.Setter; +import org.egov.common.contract.request.RequestHeader; + +import java.util.Collections; +import java.util.List; + +@Getter +@Setter +public class UserSearchRequest { + @JsonProperty("requestheader") + private RequestHeader requestHeader; + @JsonProperty("uuid") + private List uuid; + @JsonProperty("id") + private List id; + @JsonProperty("userName") + private String userName; + @JsonProperty("name") + private String name; + @JsonProperty("mobileNumber") + private String mobileNumber; + @JsonProperty("aadhaarNumber") + private String aadhaarNumber; + @JsonProperty("pan") + private String pan; + @JsonProperty("emailId") + private String emailId; + @JsonProperty("fuzzyLogic") + private boolean fuzzyLogic; + @JsonProperty("active") + @Setter + private Boolean active; + @JsonProperty("tenantId") + private String tenantId; + @JsonProperty("pageSize") + private int pageSize; + @JsonProperty("pageNumber") + private int pageNumber = 0; + @JsonProperty("sort") + private List sort = Collections.singletonList("name"); + @JsonProperty("userType") + private String userType; + @JsonProperty("roleCodes") + private List roleCodes; +} + diff --git a/core/ifix-zuul/src/main/java/org/egov/producer/Producer.java b/core/ifix-zuul/src/main/java/org/egov/producer/Producer.java new file mode 100644 index 00000000..5c8799f6 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/producer/Producer.java @@ -0,0 +1,18 @@ +package org.egov.producer; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.kafka.core.KafkaTemplate; +import org.springframework.stereotype.Service; + +@Service +@Slf4j +public class Producer { + + @Autowired + private KafkaTemplate kafkaTemplate; + + public void push(String topic, Object value) { + kafkaTemplate.send(topic, value); + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/revenues/PropertyUtility.java b/core/ifix-zuul/src/main/java/org/egov/revenues/PropertyUtility.java new file mode 100644 index 00000000..66635130 --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/revenues/PropertyUtility.java @@ -0,0 +1,10 @@ +package org.egov.revenues; + +import javax.servlet.ServletContext; + +public class PropertyUtility { + + public void updateCalculation(ServletContext ctx) { + + } +} diff --git a/core/ifix-zuul/src/main/java/org/egov/wrapper/CustomRequestWrapper.java b/core/ifix-zuul/src/main/java/org/egov/wrapper/CustomRequestWrapper.java new file mode 100644 index 00000000..f8fa4f9d --- /dev/null +++ b/core/ifix-zuul/src/main/java/org/egov/wrapper/CustomRequestWrapper.java @@ -0,0 +1,51 @@ +package org.egov.wrapper; + +import com.netflix.zuul.http.HttpServletRequestWrapper; +import com.netflix.zuul.http.ServletInputStreamWrapper; +import org.apache.commons.io.IOUtils; +import org.egov.tracer.model.CustomException; + +import javax.servlet.ServletInputStream; +import javax.servlet.http.HttpServletRequest; +import java.io.IOException; + +public class CustomRequestWrapper extends HttpServletRequestWrapper { + + private String payload; + + public CustomRequestWrapper(HttpServletRequest request) { + super(request); + convertInputStreamToString(request); + } + + private void convertInputStreamToString(HttpServletRequest request) { + try { + payload = IOUtils.toString(request.getInputStream()); + } catch (IOException e) { + throw new CustomException("INPUT_TO_STRING_CONVERSION_ERROR", e.getMessage()); + } + } + + public String getPayload() { + return payload; + } + + public void setPayload(String payload) { + this.payload = payload; + } + + @Override + public int getContentLength() { + return payload.length(); + } + + @Override + public long getContentLengthLong() { + return payload.length(); + } + + @Override + public ServletInputStream getInputStream() { + return new ServletInputStreamWrapper(payload.getBytes()); + } +} diff --git a/core/ifix-zuul/src/main/resources/application.properties b/core/ifix-zuul/src/main/resources/application.properties new file mode 100644 index 00000000..3842d53b --- /dev/null +++ b/core/ifix-zuul/src/main/resources/application.properties @@ -0,0 +1,64 @@ +#zuul.prefix=/api +#zuul.stripPrefix=true +eventlog.enabled=false +eventlog.topic=zuul.eventlog +eventlog.urls.whitelist= +eventlog.captureInputBody=false +eventlog.captureOutputBody=false +eventlog.captureOutputBodyOnlyOnError=true +zuul.health.enabled=true +security.basic.enabled=false +management.security.enabled=false +zuul.sensitiveHeaders=Cookie,Set-Cookie,auth-token +egov.auth-service-host=http://localhost:8081/ +egov.auth-service-uri=user/_details?access_token= +egov.authorize.access.control.host=http://localhost:8091/ +egov.authorize.access.control.uri=access/v1/actions/_authorize +egov.user-info-header=x-user-info +egov.open-endpoints-whitelist=/user/oauth/token,/user-otp/v1/_send,/otp/v1/_validate,/user/citizen/_create,/localization/messages,/localization/messages/v1/_search,/user/password/nologin/_update,/pgr/servicedefinition/v1/_search,/pgr/servicecategories/v1/_search,/pgr/v1/otp/_send,/pgr-master/receivingmode/v1/_search,/tenant/v1/tenant/_search,/egov-location/boundarys,/egov-location/boundarys/boundariesByBndryTypeNameAndHierarchyTypeName,/pgr-master/service/v1/_search,/egov-location/boundarys/getLocationByLocationName,/pgr-master/OTPConfig/_search,/pgr-master/serviceGroup/v1/_search,/egov-location/boundarys/isshapefileexist,/pgr/services/v1/_search,/hr-masters/hrconfigurations/_search,/collection-services/receipts/_view,/pgr-master/service/v2/_search,/pgr-master/servicedefinition/v1/_search,/citizen-services,/citizen-services/v1/requests/_search,/admin/abc,/whatsapp-webhook/messages +egov.mixed-mode-endpoints-whitelist=/pgr/seva/v1/_create,/pgr/seva/v1/_search,/pgr/seva/v1/_count,/workflow/history/v1/_search,/filestore/v1/files/id,/filestore/v1/files,/filestore/v1/files/tag,/egov-common-masters/departments/_search,/wcms/masters/categorytype/_search,/wcms/masters/pipesize/_search,/wcms/masters/sourcetype/_search,/wcms/masters/supplytype/_search,/pt-property/property/propertytypes/_search,/wcms/masters/donation/_search,/wcms/masters/propertytype-categorytype/_search,/wcms/masters/propertytype-pipesize/_search,/wcms/masters/propertytype-usagetype/_search,/wcms/masters/treatmentplant/_search,/wcms-connection/connection/_getconnectiontypes,/wcms-connection/connection/_getbillingtypes,/pt-property/properties/_search,/pt-property/property/usages/_search,/egov-idgen/id/_generate,/egf-masters/financialyears/_search,/egov-common-workflows/process/_start,/egov-common-workflows/process/_search,/egov-common-workflows/tasks,/egov-common-workflows/tasks/{id}/_update,/user/_search,/user/users/_createnovalidate,/user/users/{id}/_update,/wcms-connection/connection/_create +spring.servlet.multipart.max-file-size=5MB +spring.servlet.multipart.max-request-size=30MB +logging.pattern.console=%clr(%X{CORRELATION_ID:-}) %clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx} +#Deprecated url.lists now +#url.lists=/pt-services-v2/property/_create:/pt-services-v2/property/_create|/pt-services-v2/property/_update:/pt-services-v2/property/_update +custom.filter.posthooks=false +custom.filter.prehooks=true +url.posthook.lists= +url.prehook.lists= +zuul.routes.hooks-test.path=/admin/** +zuul.routes.hooks-test.stripPrefix=false +zuul.routes.hooks-test.url=http://localhost:5000/ +egov.custom.async.uris=/user/_logout +# KAFKA SERVER CONFIGURATIONS +kafka.config.bootstrap_server_config=kafka-0.kafka.backbone:9092 +spring.kafka.consumer.value-deserializer=org.egov.kafka.HashMapDeserializer +spring.kafka.consumer.key-deserializer=org.apache.kafka.common.serialization.StringDeserializer +spring.kafka.consumer.group-id=egov-api-gateway +spring.kafka.producer.key-serializer=org.apache.kafka.common.serialization.StringSerializer +spring.kafka.producer.value-serializer=org.springframework.kafka.support.serializer.JsonSerializer +spring.kafka.consumer.properties.spring.json.use.type.headers=false +# KAFKA PRODUCER CONFIGURATIONS +kafka.producer.config.retries_config=0 +kafka.producer.config.batch_size_config=16384 +kafka.producer.config.linger_ms_config=1 +kafka.producer.config.buffer_memory_config=33554432 +egov.custom.async.filter.topic=res-filter +tracer.filter.enabled=false +egov.statelevel.tenant=pb +# User endpoints +egov.user.search.path=/user/v1/_search +#zuul.routes.filepath=file:/home/aniket/Documents/core-services/zuul/src/main/resources/routes.properties +zuul.routes.filepath=classpath:routes.properties +home.isolation.chatbot.router.enabled=false +chatbot.context.path=/whatsapp-webhook +home.isolation.chatbot.host=http://localhost:8087/ +egov.user.isolation.service.host=http://localhost:8081/ +egov.user.isolation.service.search.path=user/v1/_search +management.endpoints.web.base-path=/ +zuul.limiter.filepath=classpath:limiter.properties +spring.redis.host=redis.backbone +spring.redis.port=6379 +keycloak.host=https://ifix-dev.ifix.org.in/ +keycloak.context-path=auth +keycloak.realm=ifix diff --git a/core/ifix-zuul/src/main/resources/limiter.properties b/core/ifix-zuul/src/main/resources/limiter.properties new file mode 100644 index 00000000..165bdb8a --- /dev/null +++ b/core/ifix-zuul/src/main/resources/limiter.properties @@ -0,0 +1,50 @@ +zuul.ratelimit.enabled=true +zuul.ratelimit.repository=REDIS +zuul.ratelimit.behind-proxy=true +zuul.ratelimit.add-response-headers=true +zuul.ratelimit.default-policy-list[0].limit=5 +zuul.ratelimit.default-policy-list[0].quota=10000 +zuul.ratelimit.default-policy-list[0].refresh-interval=60 +zuul.ratelimit.default-policy-list[0].type[0]=url=/edcr/rest/dcr/scrutinize +zuul.ratelimit.default-policy-list[0].type[1]=user +zuul.ratelimit.policy-list.user-otp[0].limit=4 +zuul.ratelimit.policy-list.user-otp[0].quota=10000 +zuul.ratelimit.policy-list.user-otp[0].refresh-interval=60 +zuul.ratelimit.policy-list.user-otp[0].type[0]=url=/user-otp +zuul.ratelimit.policy-list.user-otp[0].type[1]=origin +zuul.ratelimit.policy-list.filestore[0].limit=15 +zuul.ratelimit.policy-list.filestore[0].quota=10000 +zuul.ratelimit.policy-list.filestore[0].refresh-interval=60 +zuul.ratelimit.policy-list.filestore[0].type[0]=url=/filestore/v1/files/url +zuul.ratelimit.policy-list.filestore[0].type[1]=origin +zuul.ratelimit.policy-list.localization[0].limit=10 +zuul.ratelimit.policy-list.localization[0].quota=10000 +zuul.ratelimit.policy-list.localization[0].refresh-interval=60 +zuul.ratelimit.policy-list.localization[0].type[0]=origin +zuul.ratelimit.policy-list.user[0].limit=5 +zuul.ratelimit.policy-list.user[0].quota=10000 +zuul.ratelimit.policy-list.user[0].refresh-interval=60 +zuul.ratelimit.policy-list.user[0].type[0]=url=/user/citizen/_create +zuul.ratelimit.policy-list.user[0].type[1]=origin +zuul.ratelimit.policy-list.user[1].limit=4 +zuul.ratelimit.policy-list.user[1].quota=10000 +zuul.ratelimit.policy-list.user[1].refresh-interval=60 +zuul.ratelimit.policy-list.user[1].type[0]=url=/user/password/nologin/_update +zuul.ratelimit.policy-list.user[1].type[1]=origin +zuul.ratelimit.policy-list.tl-services[0].limit=5 +zuul.ratelimit.policy-list.tl-services[0].quota=10000 +zuul.ratelimit.policy-list.tl-services[0].refresh-interval=60 +zuul.ratelimit.policy-list.tl-services[0].type[0]=url=/tl-services/v1/_create +zuul.ratelimit.policy-list.tl-services[0].type[1]=user +zuul.ratelimit.policy-list.property-services[0].limit=5 +zuul.ratelimit.policy-list.property-services[0].quota=10000 +zuul.ratelimit.policy-list.property-services[0].refresh-interval=60 +zuul.ratelimit.policy-list.property-services[0].type[0]=url=/property-services/property/_create +zuul.ratelimit.policy-list.property-services[0].type[1]=user +zuul.ratelimit.policy-list.pgr-services[0].limit=5 +zuul.ratelimit.policy-list.pgr-services[0].quota=10000 +zuul.ratelimit.policy-list.pgr-services[0].refresh-interval=60 +zuul.ratelimit.policy-list.pgr-services[0].type[0]=url=/pgr-services/v2/request/_create +zuul.ratelimit.policy-list.pgr-services[0].type[1]=user + + diff --git a/core/ifix-zuul/src/main/resources/routes.properties b/core/ifix-zuul/src/main/resources/routes.properties new file mode 100644 index 00000000..d3d5ce6b --- /dev/null +++ b/core/ifix-zuul/src/main/resources/routes.properties @@ -0,0 +1,279 @@ +zuul.routes.pgr.path=/pgr/** +zuul.routes.pgr.stripPrefix=false +zuul.routes.pgr.url=http://localhost:8084/ +zuul.routes.pgr-master.path=/pgr-master/** +zuul.routes.pgr-master.stripPrefix=false +zuul.routes.pgr-master.url=http://localhost:8084/ +zuul.routes.user.path=/user/** +zuul.routes.user.stripPrefix=false +zuul.routes.user.url=http://localhost:8081/ +zuul.routes.location-v1.path=/egov-location/** +zuul.routes.location-v1.stripPrefix=false +zuul.routes.location-v1.url=http://localhost:8082/ +zuul.routes.filestore.path=/filestore/** +zuul.routes.filestore.stripPrefix=false +zuul.routes.filestore.url=http://localhost:8083/ +zuul.routes.localization.path=/localization/** +zuul.routes.localization.stripPrefix=false +zuul.routes.localization.url=http://localhost:8087/ +zuul.routes.pdf-service.path=/pdf-service/** +zuul.routes.pdf-service.stripPrefix=false +zuul.routes.pdf-service.url=http://localhost:8084/ +zuul.routes.otp.path=/otp/** +zuul.routes.otp.stripPrefix=false +zuul.routes.otp.url=http://localhost:8089/ +zuul.routes.user-otp.path=/user-otp/** +zuul.routes.user-otp.stripPrefix=false +zuul.routes.user-otp.url=http://localhost:8090/ +zuul.routes.workflow.path=/workflow/** +zuul.routes.workflow.stripPrefix=false +zuul.routes.workflow.url=http://localhost:8086/ +zuul.routes.hr-masters.path=/hr-masters/** +zuul.routes.hr-masters.stripPrefix=false +zuul.routes.hr-masters.url=http://localhost:8082/ +zuul.routes.egov-common-masters.path=/egov-common-masters/** +zuul.routes.egov-common-masters.stripPrefix=false +zuul.routes.egov-common-masters.url=http://localhost:8082/ +zuul.routes.hr-employee.path=/hr-employee/** +zuul.routes.hr-employee.stripPrefix=false +zuul.routes.hr-employee.url=http://localhost:8082/ +zuul.routes.hr-employee-v2.path=/hr-employee-v2/** +zuul.routes.hr-employee-v2.stripPrefix=false +zuul.routes.hr-employee-v2.url=http://localhost:8082/ +zuul.routes.hr-masters-v2.path=/hr-masters-v2/** +zuul.routes.hr-masters-v2.stripPrefix=false +zuul.routes.hr-masters-v2.url=http://localhost:8082/ +zuul.routes.hr-attendance.path=/hr-attendance/** +zuul.routes.hr-attendance.stripPrefix=false +zuul.routes.hr-attendance.url=http://localhost:8082/ +zuul.routes.hr-leave.path=/hr-leave/** +zuul.routes.hr-leave.stripPrefix=false +zuul.routes.hr-leave.url=http://localhost:8082/ +zuul.routes.hr-employee-movement.path=/hr-employee-movement/** +zuul.routes.hr-employee-movement.stripPrefix=false +zuul.routes.hr-employee-movement.url=http://localhost:8082/ +zuul.routes.egf-masters.path=/egf-masters/** +zuul.routes.egf-masters.stripPrefix=false +zuul.routes.egf-masters.url=http://localhost:8082/ +zuul.routes.asset-services.path=/asset-services/** +zuul.routes.asset-services.stripPrefix=false +zuul.routes.asset-services.url=http://localhost:8082/ +zuul.routes.lams-services.path=/lams-services/** +zuul.routes.lams-services.stripPrefix=false +zuul.routes.lams-services.url=http://localhost:8082/ +zuul.routes.demand-services.path=/demand-services/** +zuul.routes.demand-services.stripPrefix=false +zuul.routes.demand-services.url=http://localhost:8082/ +zuul.routes.billing-service.path=/billing-service/** +zuul.routes.billing-service.stripPrefix=false +zuul.routes.billing-service.url=http://localhost:8082/ +zuul.routes.collection-masters.path=/collection-masters/** +zuul.routes.collection-masters.stripPrefix=false +zuul.routes.collection-masters.url=http://localhost:9880/ +zuul.routes.collection-services.path=/collection-services/** +zuul.routes.collection-services.stripPrefix=false +zuul.routes.collection-services.url=http://localhost:9880/ +zuul.routes.collection-search-indexer.path=/collection-search-indexer/** +zuul.routes.collection-search-indexer.stripPrefix=false +zuul.routes.collection-search-indexer.url=http://localhost:9880/ +zuul.routes.egov-common-workflows.path=/egov-common-workflows/** +zuul.routes.egov-common-workflows.stripPrefix=false +zuul.routes.egov-common-workflows.url=http://localhost:8082/ +zuul.routes.egov-accesscontrol.path=/access/** +zuul.routes.egov-accesscontrol.stripPrefix=false +zuul.routes.egov-accesscontrol.url=http://localhost:8082/ +zuul.routes.tenant.path=/tenant/** +zuul.routes.tenant.stripPrefix=false +zuul.routes.tenant.url=http://localhost:8092/ +zuul.routes.wcms-masters.path=/wcms/masters/** +zuul.routes.wcms-masters.stripPrefix=false +zuul.routes.wcms-masters.url=http://localhost:8092/ +zuul.routes.wcms-connection.path=/wcms-connection/** +zuul.routes.wcms-connection.stripPrefix=false +zuul.routes.wcms-connection.url=http://localhost:8092 +zuul.routes.pt-property.path=/pt-property/** +zuul.routes.pt-property.stripPrefix=false +zuul.routes.pt-property.url=http://localhost:8092/ +zuul.routes.pt-calculator.path=/pt-calculator/** +zuul.routes.pt-calculator.stripPrefix=false +zuul.routes.pt-calculator.url=http://localhost:8092/ +zuul.routes.pt-user-enrichment.path=/pt-user-enrichment/** +zuul.routes.pt-user-enrichment.stripPrefix=false +zuul.routes.pt-user-enrichment.url=http://localhost:8092/ +zuul.routes.pt-workflow.path=/pt-workflow/** +zuul.routes.pt-workflow.stripPrefix=false +zuul.routes.pt-workflow.url=http://localhost:8092/ +zuul.routes.egov-idgen.path=/egov-idgen/** +zuul.routes.egov-idgen.stripPrefix=false +zuul.routes.egov-idgen.url=http://localhost:8092/ +zuul.routes.pt-tax-enrichment.path=/pt-tax-enrichment/** +zuul.routes.pt-tax-enrichment.stripPrefix=false +zuul.routes.pt-tax-enrichment.url=http://localhost:8084/ +zuul.routes.egf-master.path=/egf-master/** +zuul.routes.egf-master.stripPrefix=false +zuul.routes.egf-master.url=http://localhost:8084/ +zuul.routes.egf-instrument.path=/egf-instrument/** +zuul.routes.egf-instrument.stripPrefix=false +zuul.routes.egf-instrument.url=http://localhost:8084/ +zuul.routes.tl-masters.path=/tl-masters/** +zuul.routes.tl-masters.stripPrefix=false +zuul.routes.tl-masters.url=http://localhost:8084/ +zuul.routes.tl-services.path=/tl-services/** +zuul.routes.tl-services.stripPrefix=false +zuul.routes.tl-services.url=http://localhost:8084/ +zuul.routes.report.path=/report/** +zuul.routes.report.stripPrefix=false +zuul.routes.report.url=http://localhost:8084/ +zuul.routes.citizen-services.path=/citizen-services/** +zuul.routes.citizen-services.stripPrefix=false +zuul.routes.citizen-services.url=http://localhost:8084/ +zuul.routes.tl-workflow.path=/tl-workflow/** +zuul.routes.tl-workflow.stripPrefix=false +zuul.routes.tl-workflow.url=http://localhost:8084/ +zuul.routes.egf-voucher.path=/egf-voucher/** +zuul.routes.egf-voucher.stripPrefix=false +zuul.routes.egf-voucher.url=http://localhost:8084/ +zuul.routes.wcms-workflow.path=/wcms-workflow/** +zuul.routes.wcms-workflow.stripPrefix=false +zuul.routes.wcms-workflow.url=http://localhost:8084/ +zuul.routes.egf-voucher-workflow.path=/egf-voucher-workflow/** +zuul.routes.egf-voucher-workflow.stripPrefix=false +zuul.routes.egf-voucher-workflow.url=http://localhost:8084/ +zuul.routes.egov-mdms-service.path=/egov-mdms-service/** +zuul.routes.egov-mdms-service.stripPrefix=false +zuul.routes.egov-mdms-service.url=http://localhost:8084/ +zuul.routes.swm-services.path=/swm-services/** +zuul.routes.swm-services.stripPrefix=false +zuul.routes.swm-services.url=http://localhost:8084/ +zuul.routes.asset-services-maha.path=/asset-services-maha/** +zuul.routes.asset-services-maha.stripPrefix=false +zuul.routes.asset-services-maha.url=http://localhost:8084/ +zuul.routes.egov-indexer.path=/egov-indexer/** +zuul.routes.egov-indexer.stripPrefix=false +zuul.routes.egov-indexer.url=http://localhost:8084/ +zuul.routes.egov-persister.path=/egov-persister/** +zuul.routes.egov-persister.stripPrefix=false +zuul.routes.egov-persister.url=http://localhost:8084/ +zuul.routes.works-services.path=/works-services/** +zuul.routes.works-services.stripPrefix=false +zuul.routes.works-services.url=http://localhost:8084/ +zuul.routes.works-estimate.path=/works-estimate/** +zuul.routes.works-estimate.stripPrefix=false +zuul.routes.works-estimate.url=http://localhost:8084/ +zuul.routes.lcms-workflow.path=/lcms-workflow/** +zuul.routes.lcms-workflow.stripPrefix=false +zuul.routes.lcms-workflow.url=http://localhost:8084/ +zuul.routes.lcms-services.path=/lcms-services/** +zuul.routes.lcms-services.stripPrefix=false +zuul.routes.lcms-services.url=http://localhost:8084/ +zuul.routes.performance-assessment.path=/perfmanagement/** +zuul.routes.performance-assessment.stripPrefix=false +zuul.routes.performance-assessment.url=http://localhost:8084/ +zuul.routes.works-masters.path=/works-masters/** +zuul.routes.works-masters.stripPrefix=false +zuul.routes.works-masters.url=http://localhost:8084/ +zuul.routes.inventory-services.path=/inventory-services/** +zuul.routes.inventory-services.stripPrefix=false +zuul.routes.inventory-services.url=http://localhost:8084/ +zuul.routes.egov-searcher.path=/egov-searcher/** +zuul.routes.egov-searcher.stripPrefix=false +zuul.routes.egov-searcher.url=http://localhost:8084/ +zuul.routes.egov-data-uploader.path=/data-uploader/** +zuul.routes.egov-data-uploader.stripPrefix=false +zuul.routes.egov-data-uploader.url=http://localhost:8084/ +zuul.routes.works-workorder.path=/works-workorder/** +zuul.routes.works-workorder.stripPrefix=false +zuul.routes.works-workorder.url=http://localhost:8084/ +zuul.routes.works-measurementbook.path=/works-measurementbook/** +zuul.routes.works-measurementbook.stripPrefix=false +zuul.routes.works-measurementbook.url=http://localhost:8084/ +zuul.routes.egov-mdms-service-test.path=/egov-mdms-service-test/** +zuul.routes.egov-mdms-service-test.stripPrefix=false +zuul.routes.egov-mdms-service-test.url=http://localhost:8084/ +zuul.routes.egov-mdms-create.path=/egov-mdms-create/** +zuul.routes.egov-mdms-create.stripPrefix=false +zuul.routes.egov-mdms-create.url=http://localhost:8084/ +zuul.routes.egf-bill.path=/egf-bill/** +zuul.routes.egf-bill.stripPrefix=false +zuul.routes.egf-bill.url=http://localhost:8084/ +zuul.routes.works-qualitycontrol.path=/works-qualitycontrol/** +zuul.routes.works-qualitycontrol.stripPrefix=false +zuul.routes.works-qualitycontrol.url=http://localhost:8084/ +zuul.routes.egov-integration.path=/egov-common-masters/departments/_searchtest +zuul.routes.egov-integration.stripPrefix=false +zuul.routes.egov-integration.url=http://localhost:8081/ +zuul.routes.rainmaker-pgr.path=/rainmaker-pgr/** +zuul.routes.rainmaker-pgr.stripPrefix=false +zuul.routes.rainmaker-pgr.url=http://localhost:8084/ +zuul.routes.pt-services-v2.path=/pt-services-v2/** +zuul.routes.pt-services-v2.stripPrefix=false +zuul.routes.pt-services-v2.url=https://dev.digit.org/ +zuul.routes.property-services.path=/property-services/** +zuul.routes.property-services.stripPrefix=false +zuul.routes.property-services.url=https://dev.digit.org/ +zuul.routes.pt-calculator-v2.path=/pt-calculator-v2/** +zuul.routes.pt-calculator-v2.stripPrefix=false +zuul.routes.pt-calculator-v2.url=http://localhost:8084/ +zuul.routes.egov-pg-service.path=/pg-service/** +zuul.routes.egov-pg-service.stripPrefix=false +zuul.routes.egov-pg-service.url=http://localhost:8084/ +zuul.routes.egov-customization.path=/customization/** +zuul.routes.egov-customization.stripPrefix=false +zuul.routes.egov-customization.url=http://localhost:8084/ +zuul.routes.tl-calculator.path=/tl-calculator/** +zuul.routes.tl-calculator.stripPrefix=false +zuul.routes.tl-calculator.url=http://localhost:8084/ +zuul.routes.dashboard.path=/dashboard-analytics/** +zuul.routes.dashboard.stripPrefix=false +zuul.routes.dashboard.url=http://localhost:8080/ +zuul.routes.collection-receipt-voucher-consumer.path=/collection-receipt-voucher-consumer/** +zuul.routes.collection-receipt-voucher-consumer.stripPrefix=false +zuul.routes.collection-receipt-voucher-consumer.url=http://localhost:8084/ +zuul.routes.egov-index-custom-consumer.path=/egov-index-custom-consumer/** +zuul.routes.egov-index-custom-consumer.stripPrefix=false +zuul.routes.egov-index-custom-consumer.url=http://localhost:8084/ +zuul.routes.water-service.path=/restapi/watersewerage/** +zuul.routes.water-service.stripPrefix=false +zuul.routes.water-service.url=https://sunam-dev.egovernments.org/ +zuul.routes.egov-workflow-v2.path=/egov-workflow-v2/** +zuul.routes.egov-workflow-v2.stripPrefix=false +zuul.routes.egov-workflow-v2.url=http://localhost:8084/ +zuul.routes.egov-hrms.path=/egov-hrms/** +zuul.routes.egov-hrms.stripPrefix=false +zuul.routes.egov-hrms.url=http://localhost:8084/ +zuul.routes.egov-apportion-service.path=/egov-apportion-service/** +zuul.routes.egov-apportion-service.stripPrefix=false +zuul.routes.egov-apportion-service.url=http://localhost:8084/ +zuul.routes.apportion-service.path=/apportion-service/** +zuul.routes.apportion-service.stripPrefix=false +zuul.routes.apportion-service.url=http://localhost:8084/ +zuul.routes.firenoc-services.path=/firenoc-services/** +zuul.routes.firenoc-services.stripPrefix=false +zuul.routes.firenoc-services.url=http://localhost:8084/ +zuul.routes.firenoc-calculator.path=/firenoc-calculator/** +zuul.routes.firenoc-calculator.stripPrefix=false +zuul.routes.firenoc-calculator.url=http://localhost:8084/ +zuul.routes.egov-user-event.path=/egov-user-event/** +zuul.routes.egov-user-event.stripPrefix=false +zuul.routes.egov-user-event.url=http://localhost:8084/ +zuul.routes.ws-services.path=/ws-services/** +zuul.routes.ws-services.stripPrefix=false +zuul.routes.ws-services.url=http://localhost:8084/ +zuul.routes.ws-calculator.path=/ws-calculator/** +zuul.routes.ws-calculator.stripPrefix=false +zuul.routes.ws-calculator.url=http://localhost:8084/ +zuul.routes.sw-calculator.path=/sw-calculator/** +zuul.routes.sw-calculator.stripPrefix=false +zuul.routes.sw-calculator.url=http://localhost:8084/ +zuul.routes.sw-services.path=/sw-services/** +zuul.routes.sw-services.stripPrefix=false +zuul.routes.sw-services.url=http://localhost:8084/ +zuul.routes.bpa-services.path=/bpa-services/** +zuul.routes.bpa-services.stripPrefix=false +zuul.routes.bpa-services.url=http://localhost:8084/ +zuul.routes.chatbot.path=/whatsapp-webhook/** +zuul.routes.chatbot.stripPrefix=false +zuul.routes.chatbot.url=http://localhost:8012/ +zuul.routes.fiscal-event-service.path=/fiscal-event-service/** +zuul.routes.fiscal-event-service.stripPrefix=false +zuul.routes.fiscal-event-service.url=http://localhost:8031/ diff --git a/core/ifix-zuul/src/test/java/org/egov/Resources.java b/core/ifix-zuul/src/test/java/org/egov/Resources.java new file mode 100644 index 00000000..c0357045 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/Resources.java @@ -0,0 +1,22 @@ +package org.egov; + +import org.apache.commons.io.IOUtils; + +import java.io.IOException; + +public class Resources { + + public String getFileContents(String fileName) { + try { + return IOUtils.toString(this.getClass().getClassLoader() + .getResourceAsStream(fileName), "UTF-8") + .replaceAll("\n", "") + .replaceAll("\\s*\\{\\s*", "\\{") + .replaceAll("\\s*\\}\\s*", "\\}") + .replaceAll("\\s*:\\s*", ":") + .replaceAll("\\s*,\\s*", ","); + } catch (IOException e) { + throw new RuntimeException(e); + } + } +} diff --git a/core/ifix-zuul/src/test/java/org/egov/contract/ActionTest.java b/core/ifix-zuul/src/test/java/org/egov/contract/ActionTest.java new file mode 100644 index 00000000..7a4eb08e --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/contract/ActionTest.java @@ -0,0 +1,19 @@ +package org.egov.contract; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +public class ActionTest { + + @Test + public void test_should_convert_URI_with_dynamic_placeholders_to_regex_equivalent() { + final Action action = new Action(); + action.setUrl("/pgr/seva/{id}/_update"); + + final String actualRegexURI = action.getRegexUrl(); + + assertEquals("/pgr/seva/\\w+/_update", actualRegexURI); + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/post/ResponseEnhancementFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/post/ResponseEnhancementFilterTest.java new file mode 100644 index 00000000..fbf75419 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/post/ResponseEnhancementFilterTest.java @@ -0,0 +1,67 @@ +package org.egov.filters.post; + +import com.netflix.util.Pair; +import com.netflix.zuul.context.RequestContext; +import org.junit.Before; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; +import org.springframework.mock.web.MockHttpServletResponse; + +import java.util.List; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class ResponseEnhancementFilterTest { + + private ResponseEnhancementFilter filter; + + @Before + public void before() { + filter = new ResponseEnhancementFilter(); + RequestContext.getCurrentContext().clear(); + } + + @Test + public void test_should_set_response_header() { + RequestContext.getCurrentContext().set("CORRELATION_ID", "someCorrelationId"); + final MockHttpServletResponse response = new MockHttpServletResponse(); + response.setStatus(400); + RequestContext.getCurrentContext().setResponse(response); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setRequestURI("http://host/api/v1"); + RequestContext.getCurrentContext().setRequest(request); + + filter.run(); + + final List> zuulResponseHeaders = + RequestContext.getCurrentContext().getZuulResponseHeaders(); + + boolean correlationHeaderPresent = false; + boolean cacheControlHeadersPresent = false; + for (Pair header : zuulResponseHeaders) { + + if (header.first().equalsIgnoreCase("x-correlation-id")) { + correlationHeaderPresent = true; + assertEquals("someCorrelationId", header.second()); + } + + if (header.first().equalsIgnoreCase("Cache-Control")) { + cacheControlHeadersPresent = true; + assertEquals("no-cache, no-store, max-age=0, must-revalidate", header.second()); + } + } + assert correlationHeaderPresent && cacheControlHeadersPresent; + } + + @Test + public void test_should_always_execute_filter() { + assertTrue(filter.shouldFilter()); + } + + @Test + public void test_should_execute_as_last_post_filter() { + assertEquals(0, filter.filterOrder()); + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthFilterTest.java new file mode 100644 index 00000000..ca93f138 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthFilterTest.java @@ -0,0 +1,86 @@ +//package org.egov.filters.pre; +// +//import com.netflix.zuul.context.RequestContext; +//import org.egov.Resources; +//import org.egov.contract.User; +//import org.junit.Before; +//import org.junit.Test; +//import org.mockito.Mock; +//import org.mockito.MockitoAnnotations; +//import org.springframework.cloud.netflix.zuul.filters.ProxyRequestHelper; +//import org.springframework.http.HttpStatus; +//import org.springframework.mock.web.MockHttpServletRequest; +//import org.springframework.mock.web.MockHttpServletResponse; +//import org.springframework.web.client.HttpClientErrorException; +//import org.springframework.web.client.RestTemplate; +// +//import java.io.IOException; +// +//import static org.hamcrest.CoreMatchers.is; +//import static org.junit.Assert.*; +//import static org.mockito.Matchers.any; +//import static org.mockito.Matchers.eq; +//import static org.mockito.Mockito.when; +// +//public class AuthFilterTest { +// private MockHttpServletRequest request = new MockHttpServletRequest(); +// private Resources resources = new Resources(); +// +// @Mock +// private RestTemplate restTemplate; +// +// @Mock +// private ProxyRequestHelper proxyRequestHelper; +// +// private AuthFilter authFilter; +// +// private String authServiceHost = "http://localhost:8082/"; +// private String authUri = "user/_details?access_token="; +// private String userInfoHeader = "x-user-info"; +// +// @Before +// public void init() { +// MockitoAnnotations.initMocks(this); +// authFilter = new AuthFilter(proxyRequestHelper, restTemplate, authServiceHost, authUri); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.clear(); +// ctx.setRequest(request); +// } +// +// @Test +// public void testBasicProperties() { +// assertThat(authFilter.filterType(), is("pre")); +// assertThat(authFilter.filterOrder(), is(3)); +// } +// +// @Test +// public void testThatFilterShouldBeAppliedBasedOnContext() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set("shouldDoAuth", false); +// assertFalse(authFilter.shouldFilter()); +// +// ctx.set("shouldDoAuth", true); +// assertTrue(authFilter.shouldFilter()); +// } +// +// @Test +// public void testThatFilterShouldAbortIfValidatingAuthTokenFails() throws IOException { +// RequestContext ctx = RequestContext.getCurrentContext(); +// String authToken = "dummy-auth-token"; +// ctx.set("authToken", authToken); +// request.setMethod("POST"); +// ctx.setRequest(request); +// ctx.setResponse(new MockHttpServletResponse()); +// String authUrl = String.format("%s%s%s", authServiceHost, authUri, authToken); +// when(restTemplate.postForObject(eq(authUrl), any(), eq(User.class))) +// .thenThrow(new HttpClientErrorException(HttpStatus.UNAUTHORIZED)); +// +// try { +// authFilter.run(); +// assertFalse("Shouldn't reach here", true); +// } catch (RuntimeException ex) { +// assertThat(((HttpClientErrorException) ex.getCause()).getStatusCode().value(), is(401)); +// } +// } +// +//} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthPreCheckFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthPreCheckFilterTest.java new file mode 100644 index 00000000..733f5c22 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/AuthPreCheckFilterTest.java @@ -0,0 +1,344 @@ +package org.egov.filters.pre; + +import com.fasterxml.jackson.databind.JsonMappingException; +import com.netflix.zuul.context.RequestContext; +import com.netflix.zuul.monitoring.MonitoringHelper; +import org.apache.commons.io.IOUtils; +import org.egov.Utils.UserUtils; +import org.egov.contract.User; +import org.egov.exceptions.CustomException; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.rules.ExpectedException; +import org.mockito.Mockito; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.io.IOException; +import java.util.HashSet; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +public class AuthPreCheckFilterTest { + @Rule + public ExpectedException expectedEx = ExpectedException.none(); + private MockHttpServletRequest request = new MockHttpServletRequest(); + private AuthPreCheckFilter authPreCheckFilter; + private HashSet openEndpointsWhitelist = new HashSet<>(); + private HashSet anonymousEndpointsWhitelist = new HashSet<>(); + + @Before + public void init() { + openEndpointsWhitelist.add("open-endpoint1"); + openEndpointsWhitelist.add("open-endpoint2"); + anonymousEndpointsWhitelist.add("anonymous-endpoint1"); + anonymousEndpointsWhitelist.add("anonymous-endpoint2"); + UserUtils userUtils = Mockito.mock(UserUtils.class); + Mockito.when(userUtils.fetchSystemUser()).thenReturn(new User()); + authPreCheckFilter = new AuthPreCheckFilter(openEndpointsWhitelist, anonymousEndpointsWhitelist, userUtils); + RequestContext ctx = RequestContext.getCurrentContext(); + ctx.clear(); + ctx.setRequest(request); + } + + @Test + public void testBasicProperties() { + assertThat(authPreCheckFilter.filterType(), is("pre")); + assertThat(authPreCheckFilter.filterOrder(), is(1)); + assertTrue(authPreCheckFilter.shouldFilter()); + } + + @Test + public void testThatAuthShouldNotHappenForOpenEndpoints() { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("open-endpoint1"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("open-endpoint2"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldNotHappenForAnonymousGETEndpointsOnNoAuthToken() { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("anonymous-endpoint1"); + request.setMethod("GET"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("anonymous-endpoint1"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldHappenForAnonymousGETEndpointsOnAuthTokenInHeader() { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("GET"); + request.addHeader("Authorization", "Bearer token"); + + request.setRequestURI("/anonymous-endpoint1"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertTrue((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("/anonymous-endpoint1"); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertTrue((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldNotHappenForAnonymousPOSTEndpointsOnNoAuthToken() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("anonymous-endpoint1"); + request.setMethod("POST"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("anonymous-endpoint1"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldNotHappenForAnonymousPOSTEndpointsOnNoRequestHeader() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("anonymous-endpoint1"); + request.setMethod("POST"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("anonymous-endpoint1"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldNotHappenForAnonymousPUTEndpointsOnNoAuthToken() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("anonymous-endpoint1"); + request.setMethod("PUT"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("anonymous-endpoint1"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldNotHappenForAnonymousPUTEndpointsOnNorequestHeader() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setRequestURI("anonymous-endpoint1"); + request.setMethod("PUT"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + + request.setRequestURI("anonymous-endpoint1"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + authPreCheckFilter.run(); + assertFalse((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldHappenForOtherGETEndpointsOnAuthTokenInHeader() { + RequestContext ctx = RequestContext.getCurrentContext(); + request.addHeader("Authorization", "Bearer token"); + request.setMethod("GET"); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + authPreCheckFilter.run(); + assertTrue((Boolean) ctx.get("shouldDoAuth")); + } + + @Test + public void testThatAuthShouldHappenForOtherPOSTEndpointsOnAuthTokenInRequestBody() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.addHeader("auth-token", "token"); + request.setMethod("POST"); + request.setContentType("application/json"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\", \"authToken\": \"authtoken\"}}"))); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + authPreCheckFilter.run(); + assertTrue((Boolean) ctx.get("shouldDoAuth")); + assertEquals("authtoken", ctx.get("authToken")); + } + + @Test + public void testThatAuthShouldHappenForOtherPUTEndpointsOnAuthTokenInRequestBody() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.addHeader("auth-token", "token"); + request.setContentType("application/json"); + request.setMethod("PUT"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\", \"authToken\": \"authtoken\"}}"))); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + authPreCheckFilter.run(); + assertTrue((Boolean) ctx.get("shouldDoAuth")); + assertEquals("authtoken", ctx.get("authToken")); + } + + @Test(expected = CustomException.class) + public void testThatFilterShouldAbortForOtherGETEndpointsOnNoAuthToken() throws Throwable { + MonitoringHelper.initMocks(); + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("GET"); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + CustomException e = (CustomException) ex.getCause(); + assertThat(e.nStatusCode, is(401)); + throw ex.getCause(); + } + } + + @Test(expected = CustomException.class) + public void testThatFilterShouldAbortForOtherPOSTEndpointsOnNoAuthToken() throws Throwable { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("POST"); + request.setRequestURI("other-endpoint"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + CustomException e = (CustomException) ex.getCause(); + assertThat(e.nStatusCode, is(401)); + throw ex.getCause(); + } + } + + @Test(expected = CustomException.class) + public void testThatFilterShouldAbortForOtherPOSTEndpointsOnNoRequestnInfo() throws Throwable { + MonitoringHelper.initMocks(); + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("POST"); + request.setRequestURI("other-endpoint"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + CustomException e = (CustomException) ex.getCause(); + + assertThat(e.nStatusCode, is(401)); + throw ex.getCause(); + } + } + + @Test(expected = JsonMappingException.class) + public void testThatFilterShouldAbortForPOSTEndpointsOnNoRequestBody() throws Throwable { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("POST"); + request.setContentType("application/json"); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + throw ex.getCause(); + } + + } + + @Test(expected = CustomException.class) + public void testThatFilterShouldAbortForOtherPUTEndpointsOnNoAuthToken() throws Throwable { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("PUT"); + request.setRequestURI("other-endpoint"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + CustomException e = (CustomException) ex.getCause(); + assertThat(e.nStatusCode, is(401)); + throw ex.getCause(); + } + } + + @Test(expected = CustomException.class) + public void testThatFilterShouldAbortForOtherPUTEndpointsOnNoRequestnInfo() throws Throwable { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("PUT"); + request.setRequestURI("other-endpoint"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"ServiceRequest\": {\"fu\": \"bar\"}}"))); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + throw ex.getCause(); + } + } + + @Test(expected = JsonMappingException.class) + public void testThatFilterShouldAbortForPUTEndpointsOnNoRequestBody() throws Throwable { + RequestContext ctx = RequestContext.getCurrentContext(); + request.setMethod("PUT"); + request.setContentType("application/json"); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + try { + authPreCheckFilter.run(); + } catch (RuntimeException ex) { + throw ex.getCause(); + } + assertFalse(ctx.sendZuulResponse()); + assertThat(ctx.getResponseStatusCode(), is(500)); + } + + @Test + public void testThatRequestHeaderIsSanitizedForOtherPUTEndpoints() throws IOException { + RequestContext ctx = RequestContext.getCurrentContext(); + request.addHeader("auth-token", "token"); + request.setMethod("PUT"); + request.setContentType("application/json"); + request.setContent(IOUtils.toByteArray(IOUtils.toInputStream("{\"requestHeader\": {\"fu\": \"bar\", \"authToken\": \"authtoken\", \"userInfo\": {\"name\": \"fubarred\"}}}"))); + request.setRequestURI("other-endpoint"); + ctx.setRequest(request); + + authPreCheckFilter.run(); + + String expectedBody = "{\"requestHeader\":{\"fu\":\"bar\"}}"; + assertEquals(expectedBody, IOUtils.toString(ctx.getRequest().getInputStream())); + } +} diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/CorrelationIdFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/CorrelationIdFilterTest.java new file mode 100644 index 00000000..034b6dda --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/CorrelationIdFilterTest.java @@ -0,0 +1,55 @@ +package org.egov.filters.pre; + +import com.netflix.zuul.context.RequestContext; +import org.junit.Before; +import org.junit.Test; +import org.slf4j.MDC; +import org.springframework.mock.web.MockHttpServletRequest; + +import static org.junit.Assert.*; + +public class CorrelationIdFilterTest { + + private CorrelationIdFilter correlationIdFilter; + + @Before + public void before() { + correlationIdFilter = new CorrelationIdFilter(); + } + + @Test + public void test_should_set_context_with_correlation_id() { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestContext.getCurrentContext().setRequest(request); + + correlationIdFilter.run(); + + assertNotNull(RequestContext.getCurrentContext().get("CORRELATION_ID")); + } + + @Test + public void test_should_set_mdc_with_correlation_id() { + MockHttpServletRequest request = new MockHttpServletRequest(); + RequestContext.getCurrentContext().setRequest(request); + + correlationIdFilter.run(); + + assertNotNull(MDC.get("CORRELATION_ID")); + } + + @Test + public void test_should_set_filter_order_to_beginning() { + assertEquals(0, correlationIdFilter.filterOrder()); + } + + @Test + public void test_should_execute_as_pre_filter() { + assertEquals("pre", correlationIdFilter.filterType()); + } + + @Test + public void test_should_always_execute_filter() { + assertTrue(correlationIdFilter.shouldFilter()); + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacFilterTest.java new file mode 100644 index 00000000..06e3d4b2 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacFilterTest.java @@ -0,0 +1,201 @@ +//package org.egov.filters.pre; +// +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.netflix.zuul.context.RequestContext; +//import com.netflix.zuul.monitoring.MonitoringHelper; +//import org.egov.contract.Action; +//import org.egov.contract.Role; +//import org.egov.contract.User; +//import org.egov.exceptions.CustomException; +//import org.junit.Before; +//import org.junit.Ignore; +//import org.junit.Test; +//import org.mockito.MockitoAnnotations; +//import org.springframework.mock.web.MockHttpServletRequest; +//import org.springframework.test.web.client.MockRestServiceServer; +//import org.springframework.web.client.RestTemplate; +// +//import java.util.ArrayList; +//import java.util.Arrays; +//import java.util.Collections; +// +//import static org.egov.constants.RequestContextConstants.ERROR_CODE_KEY; +//import static org.egov.constants.RequestContextConstants.USER_INFO_KEY; +//import static org.hamcrest.CoreMatchers.is; +//import static org.junit.Assert.*; +//import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +//import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +//import static org.springframework.test.web.client.response.MockRestResponseCreators.withUnauthorizedRequest; +// +// +//public class RbacFilterTest { +// +// private MockHttpServletRequest request; +// +// private RestTemplate restTemplate = new RestTemplate(); +// +// private RbacFilter rbacFilter; +// +// private MockRestServiceServer mockServer = MockRestServiceServer.bindTo(restTemplate).build(); +// +// +// @Before +// public void init() { +// MockitoAnnotations.initMocks(this); +// request = new MockHttpServletRequest(); +// rbacFilter = new RbacFilter(restTemplate, "http://localhost:8091/access/v1/actions/_authorize", new ObjectMapper()); +// +// RequestContext.getCurrentContext().clear(); +// } +// +// @Test +// public void testThatFilterOrderIs3() throws Exception { +// assertThat(rbacFilter.filterOrder(), is(4)); +// } +// +// @Test +// public void testThatFilterShouldNotRunWhenRbacIsNotRequired() throws Exception { +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set("shouldDoRbac", false); +// assertFalse(rbacFilter.shouldFilter()); +// } +// +// @Test(expected = CustomException.class) +// public void shouldAbortWhenUserIsRequestingUnauthorizedURI() throws Throwable { +// MonitoringHelper.initMocks(); +// User user = new User(); +// Action action1 = new Action(); +// action1.setUrl("/pgr/seva"); +// user.setActions(new ArrayList<>(Collections.singletonList(action1))); +// user.setRoles(Collections.singletonList(new Role(10L, "CITIZEN", "CITIZEN", "default"))); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(USER_INFO_KEY, user); +// +// mockServer.expect(requestTo("http://localhost:8091/access/v1/actions/_authorize")) +// .andRespond(withUnauthorizedRequest()); +// +// request.setRequestURI("/hr-masters/do/something"); +// ctx.setRequest(request); +// try { +// rbacFilter.run(); +// } catch (RuntimeException ex) { +// CustomException e = (CustomException) ex.getCause(); +// assertThat(e.nStatusCode, is(403)); +// throw ex.getCause(); +// } +// +// assertForbiddenResponse(ctx); +// } +// +// @Test +// public void shouldNotAbortWhenUserIsRequestingAuthorizedURI() throws Exception { +// User user = new User(); +// Action action1 = new Action(); +// action1.setUrl("/pgr/seva"); +// user.setActions(new ArrayList<>(Arrays.asList(action1))); +// user.setRoles(Collections.singletonList(new Role(10L, "CITIZEN", "CITIZEN", "default"))); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(USER_INFO_KEY, user); +// +// request.setRequestURI("/pgr/seva"); +// ctx.setRequest(request); +// +// mockServer.expect(requestTo("http://localhost:8091/access/v1/actions/_authorize")) +// .andRespond(withSuccess()); +// +// rbacFilter.run(); +// +// assertEquals(null, ctx.get(ERROR_CODE_KEY)); +// } +// +// @Test(expected = CustomException.class) +// public void shouldAbortWhenUserDoesNotHaveAnyAuthorizedURI() throws Throwable { +// MonitoringHelper.initMocks(); +// RequestContext ctx = RequestContext.getCurrentContext(); +// request.setRequestURI("/hr-masters/do/something"); +// ctx.setRequest(request); +// User user = new User(); +// user.setActions(new ArrayList<>()); +// user.setRoles(Collections.singletonList(new Role(10L, "CITIZEN", "CITIZEN", "default"))); +// ctx.set(USER_INFO_KEY, user); +// +// mockServer.expect(requestTo("http://localhost:8091/access/v1/actions/_authorize")) +// .andRespond(withUnauthorizedRequest()); +// +// try { +// rbacFilter.run(); +// } catch (RuntimeException ex) { +// CustomException e = (CustomException) ex.getCause(); +// assertThat(e.nStatusCode, is(403)); +// throw ex.getCause(); +// } +// +// assertForbiddenResponse(ctx); +// } +// +// @Test +// @Ignore +// public void shouldNotAbortWhenUserIsRequestingURIAndAuthorizedURIHasDynamicPlaceHolders() throws Exception { +// User user = new User(); +// Action action1 = new Action(); +// action1.setUrl("/pgr/seva/{id}/_update"); +// user.setActions(new ArrayList<>(Arrays.asList(action1))); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(USER_INFO_KEY, user); +// request.setRequestURI("/pgr/seva/123/_update"); +// ctx.setRequest(request); +// +// System.out.println(action1.getRegexUrl()); +// System.out.println("/pgr/seva/123/_update".matches(action1.getRegexUrl())); +// +// rbacFilter.run(); +// +// assertEquals(null, ctx.get(ERROR_CODE_KEY)); +// } +// +// @Test +// @Ignore +// public void shouldNotAbortWhenUserIsRequestingURIAndAuthorizedURIHasMultipleDynamicPlaceHolders() throws Exception { +// User user = new User(); +// Action action1 = new Action(); +// action1.setUrl("/pgr/seva/{tenantCode}/{id}/_update"); +// user.setActions(new ArrayList<>(Arrays.asList(action1))); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(USER_INFO_KEY, user); +// request.setRequestURI("/pgr/seva/default/123/_update"); +// ctx.setRequest(request); +// rbacFilter.run(); +// +// assertEquals(null, ctx.get(ERROR_CODE_KEY)); +// } +// +// @Test(expected = CustomException.class) +// @Ignore +// public void shouldAbortWhenUserIsRequestingURIAndAuthorizedURIWithDynamicPlaceHoldersDoesNotMatch() throws Throwable { +// MonitoringHelper.initMocks(); +// User user = new User(); +// Action action1 = new Action(); +// action1.setUrl("/pgr/seva/{id}/_create"); +// user.setActions(new ArrayList<>(Arrays.asList(action1))); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.set(USER_INFO_KEY, user); +// +// request.setRequestURI("/pgr/seva/123/_update"); +// ctx.setRequest(request); +// try { +// rbacFilter.run(); +// } catch (RuntimeException ex) { +// CustomException e = (CustomException) ex.getCause(); +// assertThat(e.nStatusCode, is(403)); +// throw ex.getCause(); +// } +// +// assertForbiddenResponse(ctx); +// } +// +// private void assertForbiddenResponse(RequestContext ctx) { +// assertEquals(403, ctx.get(ERROR_CODE_KEY)); +// assertFalse(ctx.sendZuulResponse()); +// } +// +//} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacPreCheckFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacPreCheckFilterTest.java new file mode 100644 index 00000000..8d1adee4 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RbacPreCheckFilterTest.java @@ -0,0 +1,67 @@ +//package org.egov.filters.pre; +// +//import com.netflix.zuul.context.RequestContext; +//import org.junit.Before; +//import org.junit.Test; +//import org.springframework.mock.web.MockHttpServletRequest; +// +//import java.util.HashSet; +// +//import static org.hamcrest.CoreMatchers.is; +//import static org.junit.Assert.*; +// +//public class RbacPreCheckFilterTest { +// private MockHttpServletRequest request = new MockHttpServletRequest(); +// +// private HashSet openEndpointsWhitelist = new HashSet<>(); +// private HashSet anonymousEndpointsWhitelist = new HashSet<>(); +// +// private RbacPreCheckFilter rbacPreCheckFilter; +// +// @Before +// public void init() { +// openEndpointsWhitelist.add("/user/_details"); +// openEndpointsWhitelist.add("open-endpoint2"); +// anonymousEndpointsWhitelist.add("/pgr/complaintTypeCategories"); +// anonymousEndpointsWhitelist.add("anonymous-endpoint2"); +// rbacPreCheckFilter = new RbacPreCheckFilter(openEndpointsWhitelist, anonymousEndpointsWhitelist); +// RequestContext ctx = RequestContext.getCurrentContext(); +// ctx.clear(); +// ctx.setRequest(request); +// +// } +// +// @Test +// public void testBasicProperties() { +// assertThat(rbacPreCheckFilter.filterType(), is("pre")); +// assertThat(rbacPreCheckFilter.filterOrder(), is(2)); +// } +// +// @Test +// public void testThatRbacCheckShouldNotHappenForOpenEndpoints() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// request.setRequestURI("/user/_details"); +// ctx.setRequest(request); +// rbacPreCheckFilter.run(); +// assertFalse((Boolean) ctx.get("shouldDoRbac")); +// } +// +// @Test +// public void test_That_Rbac_Check_Sould_Not_Happen_For_AnonymousEndPoints() { +// RequestContext ctx = RequestContext.getCurrentContext(); +// request.setRequestURI("/pgr/complaintTypeCategories"); +// ctx.setRequest(request); +// rbacPreCheckFilter.run(); +// assertFalse((Boolean) ctx.get("shouldDoRbac")); +// } +// +// @Test +// public void test_should_return_true_when_uri_is_not_in_open_or_anonymous_endpoint_and_uri_is_present_in_rbacwhitelist() throws Exception { +// RequestContext ctx = RequestContext.getCurrentContext(); +// request.setRequestURI("/pgr/seva/_create"); +// ctx.setRequest(request); +// rbacPreCheckFilter.run(); +// assertTrue((Boolean) ctx.get("shouldDoRbac")); +// } +// +//} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/filters/pre/RequestEnrichmentFilterTest.java b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RequestEnrichmentFilterTest.java new file mode 100644 index 00000000..79d40cef --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/filters/pre/RequestEnrichmentFilterTest.java @@ -0,0 +1,150 @@ +package org.egov.filters.pre; + +import com.netflix.zuul.context.RequestContext; +import org.apache.commons.io.IOUtils; +import org.egov.Resources; +import org.egov.contract.Role; +import org.egov.contract.User; +import org.egov.contract.UserInfo; +import org.junit.Before; +import org.junit.Test; +import org.springframework.http.MediaType; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +public class RequestEnrichmentFilterTest { + + private RequestEnrichmentFilter filter; + private Resources resources = new Resources(); + + @Before + public void before() { + filter = new RequestEnrichmentFilter(); + RequestContext.getCurrentContext().clear(); + } + + @Test + public void test_should_set_filter_order_to_execute_last() { + assertEquals(5, filter.filterOrder()); + } + + @Test + public void test_should_always_execute_filter() { + assertTrue(filter.shouldFilter()); + } + + @Test + public void test_should_add_correlation_id_request_header() { + final RequestContext currentContext = RequestContext.getCurrentContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + currentContext.setRequest(request); + final String expectedCorrelationId = "someCorrelationId"; + currentContext.set("CORRELATION_ID", expectedCorrelationId); + + filter.run(); + + final Map zuulRequestHeaders = currentContext.getZuulRequestHeaders(); + assertEquals(2, zuulRequestHeaders.size()); + assertEquals(expectedCorrelationId, zuulRequestHeaders.get("x-correlation-id")); + } + + @Test + public void test_should_add_correlation_id_to_request_info_section_of_request_body() throws IOException { + final RequestContext currentContext = RequestContext.getCurrentContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setRequestURI("http://foo/bar/v1/_create"); + request.setContentType(MediaType.APPLICATION_JSON_UTF8_VALUE); + request.setContent(getContent("postRequestFromConsumer.json")); + currentContext.setRequest(request); + final String expectedCorrelationId = "someCorrelationId"; + currentContext.set("CORRELATION_ID", expectedCorrelationId); + currentContext.set("USER_INFO", null); + + filter.run(); + + String expectedBody = resources.getFileContents("postRequestWithCorrelationId.json"); + assertEquals(expectedBody, IOUtils.toString(currentContext.getRequest().getInputStream())); + } + + @Test + public void test_should_add_user_info_to_request_info_section_of_request_body() throws IOException { + final RequestContext currentContext = RequestContext.getCurrentContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setRequestURI("http://foo/bar/v1/_create"); + request.setContent(getContent("postRequestFromConsumer.json")); + request.setContentType(MediaType.APPLICATION_JSON_VALUE); + currentContext.setRequest(request); + final String expectedCorrelationId = "someCorrelationId"; + currentContext.set("CORRELATION_ID", expectedCorrelationId); + currentContext.set("USER_INFO", getUser()); + + filter.run(); + + String expectedBody = resources.getFileContents("enrichedPostRequest.json"); + assertEquals(expectedBody, IOUtils.toString(currentContext.getRequest().getInputStream())); + } + + @Test + public void test_should_add_user_info_request_header_for_GET_request_type() throws IOException { + final RequestContext currentContext = RequestContext.getCurrentContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("GET"); + request.setRequestURI("http://foo/bar/v1/_search"); + currentContext.setRequest(request); + currentContext.set("CORRELATION_ID", "someCorrelationId"); + currentContext.set("USER_INFO", getUser()); + + filter.run(); + + String expectedHeaderValue = resources.getFileContents("userInfoHeader.json"); + final Map zuulRequestHeaders = currentContext.getZuulRequestHeaders(); + assertEquals(expectedHeaderValue, zuulRequestHeaders.get("x-user-info")); + } + + @Test + public void test_should_not_modify_request_body_when_request_info_section_is_not_present() throws IOException { + final RequestContext currentContext = RequestContext.getCurrentContext(); + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setMethod("POST"); + request.setRequestURI("http://foo/bar/v1/_create"); + request.setContent(getContent("postRequestWithoutRequestHeaderFromConsumer.json")); + currentContext.setRequest(request); + final String expectedCorrelationId = "someCorrelationId"; + currentContext.set("CORRELATION_ID", expectedCorrelationId); + currentContext.set("USER_INFO", getUser()); + + filter.run(); + + String expectedBody = resources.getFileContents("postRequestWithoutRequestHeaderFromConsumer.json"); + assertEquals(expectedBody, IOUtils.toString(currentContext.getRequest().getInputStream())); + } + + private UserInfo getUser() { + UserInfo mockUserInfo = new UserInfo(); + mockUserInfo.setUuid("abcd"); + mockUserInfo.setTenants(Arrays.asList(new String[]{"pb"})); + mockUserInfo.setRoles(Arrays.asList(new String[]{"fiscal-event-producer"})); + mockUserInfo.setAttributes(null); + return mockUserInfo; + } + + private byte[] getContent(String fileName) { + try { + return IOUtils.toByteArray(IOUtils.toInputStream(resources.getFileContents(fileName))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/model/RequestBodyInspectorTest.java b/core/ifix-zuul/src/test/java/org/egov/model/RequestBodyInspectorTest.java new file mode 100644 index 00000000..02aeba79 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/model/RequestBodyInspectorTest.java @@ -0,0 +1,89 @@ +package org.egov.model; + +import org.junit.Test; + +import java.util.HashMap; +import java.util.Set; + +import static org.junit.Assert.*; + +public class RequestBodyInspectorTest { + + @Test + public void test_should_return_request_info_when_request_info_container_field_name_has_pascal_case() { + final HashMap requestBody = new HashMap<>(); + final HashMap requestHeaderBody = new HashMap<>(); + requestBody.put("requestHeader", requestHeaderBody); + + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + assertEquals(requestHeaderBody, requestBodyInspector.getRequestHeader()); + } + + @Test + public void test_should_return_request_info_when_request_info_container_field_name_has_camel_case() { + final HashMap requestBody = new HashMap<>(); + final HashMap requestHeaderBody = new HashMap<>(); + requestBody.put("requestHeader", requestHeaderBody); + + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + assertEquals(requestHeaderBody, requestBodyInspector.getRequestHeader()); + } + + @Test + public void test_should_return_null_when_request_body_is_empty() { + final HashMap requestBody = new HashMap<>(); + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + assertNull(requestBodyInspector.getRequestHeader()); + } + + @Test + public void test_should_return_null_when_request_body_does_not_have_request_info() { + final HashMap requestBody = new HashMap<>(); + requestBody.put("someField", new HashMap<>()); + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + assertNull(requestBodyInspector.getRequestHeader()); + } + + @Test + public void test_should_update_request_info() { + final HashMap requestBody = new HashMap<>(); + final HashMap originalRequestHeaderBody = new HashMap<>(); + requestBody.put("requestHeader", originalRequestHeaderBody); + + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + final HashMap updatedRequestHeader = new HashMap<>(); + updatedRequestHeader.put("foo", "bar"); + + requestBodyInspector.updateRequestHeader(updatedRequestHeader); + + final HashMap actualRequestBody = requestBodyInspector.getRequestBody(); + final HashMap actualRequestHeader = + (HashMap) actualRequestBody.get("requestHeader"); + assertNotNull(actualRequestHeader); + assertTrue(actualRequestHeader.containsKey("foo")); + } + + @Test + public void test_should_not_update_request_body_with_new_request_info_when_original_request_body_does_not_have_request_info_field() { + final HashMap requestBody = new HashMap<>(); + requestBody.put("foo", new HashMap<>()); + + final RequestBodyInspector requestBodyInspector = new RequestBodyInspector(requestBody); + + final HashMap updatedRequestHeader = new HashMap<>(); + updatedRequestHeader.put("userInfo", "user"); + + requestBodyInspector.updateRequestHeader(updatedRequestHeader); + + final HashMap actualRequestBody = requestBodyInspector.getRequestBody(); + final Set keys = actualRequestBody.keySet(); + assertEquals(1, keys.size()); + assertTrue(keys.contains("foo")); + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/java/org/egov/wrapper/CustomRequestWrapperTest.java b/core/ifix-zuul/src/test/java/org/egov/wrapper/CustomRequestWrapperTest.java new file mode 100644 index 00000000..b199bde5 --- /dev/null +++ b/core/ifix-zuul/src/test/java/org/egov/wrapper/CustomRequestWrapperTest.java @@ -0,0 +1,57 @@ +package org.egov.wrapper; + +import org.apache.commons.io.IOUtils; +import org.egov.Resources; +import org.junit.Test; +import org.springframework.mock.web.MockHttpServletRequest; + +import java.io.IOException; +import java.io.StringReader; + +import static org.junit.Assert.assertEquals; + +public class CustomRequestWrapperTest { + private final Resources resources = new Resources(); + + @Test + public void test_should_allow_play_load_to_be_retrieved_multiple_times() throws IOException { + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String expectedContent = "foobar"; + request.setContent(IOUtils.toByteArray(new StringReader(expectedContent))); + final CustomRequestWrapper wrapper = new CustomRequestWrapper(request); + + assertEquals(expectedContent, new String(IOUtils.toByteArray(wrapper.getInputStream()))); + assertEquals(expectedContent, new String(IOUtils.toByteArray(wrapper.getInputStream()))); + } + + @Test + public void test_should_allow_play_load_to_set() throws IOException { + final MockHttpServletRequest request = new MockHttpServletRequest(); + final String expectedContent = "foobar"; + request.setContent(IOUtils.toByteArray(new StringReader("originalContent"))); + final CustomRequestWrapper wrapper = new CustomRequestWrapper(request); + + wrapper.setPayload(expectedContent); + + assertEquals(expectedContent, new String(IOUtils.toByteArray(wrapper.getInputStream()))); + } + + @Test + public void test_should_return_pay_load_length() throws IOException { + final MockHttpServletRequest request = new MockHttpServletRequest(); + request.setContent(IOUtils.toByteArray(new StringReader("foobar"))); + final CustomRequestWrapper wrapper = new CustomRequestWrapper(request); + + assertEquals(6, wrapper.getContentLength()); + assertEquals(6, wrapper.getContentLengthLong()); + } + + private byte[] getContent(String fileName) { + try { + return IOUtils.toByteArray(IOUtils.toInputStream(resources.getFileContents(fileName))); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/application.properties b/core/ifix-zuul/src/test/resources/application.properties new file mode 100644 index 00000000..02635647 --- /dev/null +++ b/core/ifix-zuul/src/test/resources/application.properties @@ -0,0 +1,59 @@ +zuul.routes.pgr.path=/pgr/** +zuul.routes.pgr.stripPrefix=false +zuul.routes.pgr.url=http://localhost:8081/ +zuul.routes.user.path=/user/** +zuul.routes.user.stripPrefix=false +zuul.routes.user.url=http://localhost:8082/ +zuul.routes.location-v1.path=/v1/location/** +zuul.routes.location-v1.stripPrefix=false +zuul.routes.location-v1.url=http://localhost:8082/ +zuul.routes.location-a1.path=/a1/location/** +zuul.routes.location-a1.stripPrefix=false +zuul.routes.location-a1.url=http://localhost:8082/ +zuul.routes.filestore.path=/filestore/** +zuul.routes.filestore.stripPrefix=false +zuul.routes.filestore.url=http://localhost:8082/ +zuul.routes.localization.path=/localization/** +zuul.routes.localization.stripPrefix=false +zuul.routes.localization.url=http://localhost:8082/ +zuul.routes.otp.path=/otp/** +zuul.routes.otp.stripPrefix=false +zuul.routes.otp.url=http://localhost:8082/ +zuul.routes.user-otp.path=/user-otp/** +zuul.routes.user-otp.stripPrefix=false +zuul.routes.user-otp.url=http://localhost:8082/ +zuul.routes.workflow.path=/workflow/** +zuul.routes.workflow.stripPrefix=false +zuul.routes.workflow.url=http://localhost:8082/ +zuul.routes.hr-masters.path=/hr-masters/** +zuul.routes.hr-masters.stripPrefix=false +zuul.routes.hr-masters.url=http://localhost:8082/ +zuul.routes.egov-common-masters.path=/egov-common-masters/** +zuul.routes.egov-common-masters.stripPrefix=false +zuul.routes.egov-common-masters.url=http://localhost:8082/ +zuul.routes.hr-employee.path=/hr-employee/** +zuul.routes.hr-employee.stripPrefix=false +zuul.routes.hr-employee.url=http://localhost:8082/ +zuul.routes.hr-attendance.path=/hr-employee/** +zuul.routes.hr-attendance.stripPrefix=false +zuul.routes.hr-attendance.url=http://localhost:8082/ +zuul.routes.eis.path=/eis/** +zuul.routes.eis.stripPrefix=false +zuul.routes.eis.url=http://localhost:8082/ +zuul.routes.egf-masters.path=/egf-masters/** +zuul.routes.egf-masters.stripPrefix=false +zuul.routes.egf-masters.url=http://localhost:8082/ +zuul.routes.asset-services.path=/asset-services/** +zuul.routes.asset-services.stripPrefix=false +zuul.routes.asset-services.url=http://localhost:8082/ +zuul.routes.lams-services.path=/lams-services/** +zuul.routes.lams-services.stripPrefix=false +zuul.routes.lams-services.url=http://localhost:8082/ +zuul.sensitiveHeaders=Cookie,Set-Cookie,x-user-info,auth-token +egov.auth-service-host=http://localhost:8082/ +egov.auth-service-uri=user/_details?access_token= +egov.user-info-header=x-user-info +egov.open-endpoints-whitelist=/user/_login,/user/_details +egov.mixed-mode-endpoints-whitelist=/pgr/complaintTypeCategories,/pgr/seva +egov.authorize.access.control.host=http://localhost:8091/ +egov.authorize.access.control.uri=access/v1/actions/_authorize \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/enrichedPostRequest.json b/core/ifix-zuul/src/test/resources/enrichedPostRequest.json new file mode 100644 index 00000000..06e8e55e --- /dev/null +++ b/core/ifix-zuul/src/test/resources/enrichedPostRequest.json @@ -0,0 +1,13 @@ +{ + "requestHeader": { + "fu": "bar", + "authToken": "dummy-auth-token", + "userInfo": { + "uuid": "abcd", + "roles": ["fiscal-event-producer"], + "tenants": ["pb"], + "attributes": null + }, + "correlationId": "someCorrelationId" + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/postRequestFromConsumer.json b/core/ifix-zuul/src/test/resources/postRequestFromConsumer.json new file mode 100644 index 00000000..3107ac01 --- /dev/null +++ b/core/ifix-zuul/src/test/resources/postRequestFromConsumer.json @@ -0,0 +1,6 @@ +{ + "requestHeader": { + "fu": "bar", + "authToken": "dummy-auth-token" + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/postRequestWithCorrelationId.json b/core/ifix-zuul/src/test/resources/postRequestWithCorrelationId.json new file mode 100644 index 00000000..29fb750a --- /dev/null +++ b/core/ifix-zuul/src/test/resources/postRequestWithCorrelationId.json @@ -0,0 +1,7 @@ +{ + "requestHeader": { + "fu": "bar", + "authToken": "dummy-auth-token", + "correlationId": "someCorrelationId" + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/postRequestWithoutRequestHeaderFromConsumer.json b/core/ifix-zuul/src/test/resources/postRequestWithoutRequestHeaderFromConsumer.json new file mode 100644 index 00000000..797a4058 --- /dev/null +++ b/core/ifix-zuul/src/test/resources/postRequestWithoutRequestHeaderFromConsumer.json @@ -0,0 +1,5 @@ +{ + "foo": { + "bar": "bar1" + } +} \ No newline at end of file diff --git a/core/ifix-zuul/src/test/resources/userInfoHeader.json b/core/ifix-zuul/src/test/resources/userInfoHeader.json new file mode 100644 index 00000000..51a0d4c5 --- /dev/null +++ b/core/ifix-zuul/src/test/resources/userInfoHeader.json @@ -0,0 +1,6 @@ +{ + "uuid": "abcd", + "roles": ["fiscal-event-producer"], + "tenants": ["pb"], + "attributes": null +} \ No newline at end of file From 30a315fe4cdba02abdf7ecc15a9bf4eb587e90f8 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 25 Aug 2021 12:21:57 +0530 Subject: [PATCH 10/67] Keycloak (#31) * Update build-config.yml (#3) * Update build-config.yml (#4) * Update build-config.yml (#5) * Updated Dockerfile base image (#6) * Update build-config.yml (#12) * Instructions for Creating Client * Added ifix-realm and instructions to import it Co-authored-by: rushang7-eGov Co-authored-by: Rushang Dhanesha Co-authored-by: pintu-eGov --- core/keycloak/INSTRUCTIONS.md | 25 + core/keycloak/ifix-realm.json | 1471 +++++++++++++++++++++++++++++++++ 2 files changed, 1496 insertions(+) create mode 100644 core/keycloak/INSTRUCTIONS.md create mode 100644 core/keycloak/ifix-realm.json diff --git a/core/keycloak/INSTRUCTIONS.md b/core/keycloak/INSTRUCTIONS.md new file mode 100644 index 00000000..508702af --- /dev/null +++ b/core/keycloak/INSTRUCTIONS.md @@ -0,0 +1,25 @@ +# Keycloak Setup + +## Import Realm + +1. Open the keycloak console +2. Near the top-left corner in the realm drop down menu, select **Add Realm**. +3. Select the [ifix-realm.json](./ifix-realm.json) file. + +## Creating Clients + +1. From the Clients section of Keycloak Admin Console, create a client. +2. Provide unique username for the client. +3. Go to client's settings +4. Change Access Type to **confidential** +5. Turn on **Service Account Enabled** +6. In the **Valid Redirect URIs** field provide the root url of the iFIX Instance. (Not important for our purposes but need to set it because it is mandatory) +7. And Save these changes +8. In the **Service Account Roles** tab, assign the role "fiscal-event-producer" +9. In the **Mappers** tab, create a new mapper to associate the client with a tenantId + a. Select Mapper Type to be Hardcoded claim + b. In Claim Name, write "tenantId" + c. In Claim value, write the under which the client is being created. (For example, "pb") + d. Select Claim Json Type to be String + +Now you can get the credentials from the **Credentials** tab and configure them in the client's system. \ No newline at end of file diff --git a/core/keycloak/ifix-realm.json b/core/keycloak/ifix-realm.json new file mode 100644 index 00000000..d0df4334 --- /dev/null +++ b/core/keycloak/ifix-realm.json @@ -0,0 +1,1471 @@ +{ + "id": "ifix", + "realm": "ifix", + "notBefore": 0, + "defaultSignatureAlgorithm": "RS256", + "revokeRefreshToken": false, + "refreshTokenMaxReuse": 0, + "accessTokenLifespan": 2592000, + "accessTokenLifespanForImplicitFlow": 2592000, + "ssoSessionIdleTimeout": 2592000, + "ssoSessionMaxLifespan": 2592000, + "ssoSessionIdleTimeoutRememberMe": 0, + "ssoSessionMaxLifespanRememberMe": 0, + "offlineSessionIdleTimeout": 2592000, + "offlineSessionMaxLifespanEnabled": false, + "offlineSessionMaxLifespan": 5184000, + "clientSessionIdleTimeout": 0, + "clientSessionMaxLifespan": 0, + "clientOfflineSessionIdleTimeout": 0, + "clientOfflineSessionMaxLifespan": 0, + "accessCodeLifespan": 60, + "accessCodeLifespanUserAction": 300, + "accessCodeLifespanLogin": 1800, + "actionTokenGeneratedByAdminLifespan": 43200, + "actionTokenGeneratedByUserLifespan": 300, + "oauth2DeviceCodeLifespan": 600, + "oauth2DevicePollingInterval": 5, + "enabled": true, + "sslRequired": "external", + "registrationAllowed": false, + "registrationEmailAsUsername": false, + "rememberMe": false, + "verifyEmail": false, + "loginWithEmailAllowed": true, + "duplicateEmailsAllowed": false, + "resetPasswordAllowed": false, + "editUsernameAllowed": false, + "bruteForceProtected": false, + "permanentLockout": false, + "maxFailureWaitSeconds": 900, + "minimumQuickLoginWaitSeconds": 60, + "waitIncrementSeconds": 60, + "quickLoginCheckMilliSeconds": 1000, + "maxDeltaTimeSeconds": 43200, + "failureFactor": 30, + "roles": { + "realm": [ + { + "id": "f76cafde-a243-4447-ad3a-484ddbacaf5d", + "name": "fiscal-event-producer", + "composite": false, + "clientRole": false, + "containerId": "ifix", + "attributes": {} + }, + { + "id": "d705e411-43c8-41fa-be25-2b16efa370ad", + "name": "default-roles-ifix", + "description": "${role_default-roles}", + "composite": true, + "composites": { + "client": { + "account": [ + "manage-account", + "view-profile" + ] + } + }, + "clientRole": false, + "containerId": "ifix", + "attributes": {} + } + ] + }, + "groups": [], + "defaultRole": { + "id": "d705e411-43c8-41fa-be25-2b16efa370ad", + "name": "default-roles-ifix", + "description": "${role_default-roles}", + "composite": true, + "clientRole": false, + "containerId": "ifix" + }, + "requiredCredentials": [ + "password" + ], + "otpPolicyType": "totp", + "otpPolicyAlgorithm": "HmacSHA1", + "otpPolicyInitialCounter": 0, + "otpPolicyDigits": 6, + "otpPolicyLookAheadWindow": 1, + "otpPolicyPeriod": 30, + "otpSupportedApplications": [ + "FreeOTP", + "Google Authenticator" + ], + "webAuthnPolicyRpEntityName": "keycloak", + "webAuthnPolicySignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyRpId": "", + "webAuthnPolicyAttestationConveyancePreference": "not specified", + "webAuthnPolicyAuthenticatorAttachment": "not specified", + "webAuthnPolicyRequireResidentKey": "not specified", + "webAuthnPolicyUserVerificationRequirement": "not specified", + "webAuthnPolicyCreateTimeout": 0, + "webAuthnPolicyAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyAcceptableAaguids": [], + "webAuthnPolicyPasswordlessRpEntityName": "keycloak", + "webAuthnPolicyPasswordlessSignatureAlgorithms": [ + "ES256" + ], + "webAuthnPolicyPasswordlessRpId": "", + "webAuthnPolicyPasswordlessAttestationConveyancePreference": "not specified", + "webAuthnPolicyPasswordlessAuthenticatorAttachment": "not specified", + "webAuthnPolicyPasswordlessRequireResidentKey": "not specified", + "webAuthnPolicyPasswordlessUserVerificationRequirement": "not specified", + "webAuthnPolicyPasswordlessCreateTimeout": 0, + "webAuthnPolicyPasswordlessAvoidSameAuthenticatorRegister": false, + "webAuthnPolicyPasswordlessAcceptableAaguids": [], + "clientProfiles": {}, + "clientPolicies": {}, + "clientScopes": [ + { + "id": "3f6d2dfc-594a-4687-8a39-0db42cdfa75e", + "name": "microprofile-jwt", + "description": "Microprofile - JWT built-in scope", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "false" + }, + "protocolMappers": [ + { + "id": "9c9e449a-9532-4715-ab30-7fa61669074a", + "name": "groups", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "multivalued": "true", + "user.attribute": "foo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "groups", + "jsonType.label": "String" + } + }, + { + "id": "f76ae324-654f-46ec-834b-5783b74dc9f8", + "name": "upn", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "upn", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "1eeaeab8-d220-4780-a809-e3550121b9e9", + "name": "web-origins", + "description": "OpenID Connect scope for add allowed web origins to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "false", + "consent.screen.text": "" + }, + "protocolMappers": [ + { + "id": "5bc055df-3342-4d42-8634-92e2065464cd", + "name": "allowed web origins", + "protocol": "openid-connect", + "protocolMapper": "oidc-allowed-origins-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "f75cb86d-fc7e-4efb-a411-effb7f566749", + "name": "offline_access", + "description": "OpenID Connect built-in scope: offline_access", + "protocol": "openid-connect", + "attributes": { + "consent.screen.text": "${offlineAccessScopeConsentText}", + "display.on.consent.screen": "true" + } + }, + { + "id": "2a0e5f63-be42-4bd9-8982-f4f2750ff96a", + "name": "address", + "description": "OpenID Connect built-in scope: address", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${addressScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "ed622591-ccdc-43a9-ad37-68f5cb331453", + "name": "address", + "protocol": "openid-connect", + "protocolMapper": "oidc-address-mapper", + "consentRequired": false, + "config": { + "user.attribute.formatted": "formatted", + "user.attribute.country": "country", + "user.attribute.postal_code": "postal_code", + "userinfo.token.claim": "true", + "user.attribute.street": "street", + "id.token.claim": "true", + "user.attribute.region": "region", + "access.token.claim": "true", + "user.attribute.locality": "locality" + } + } + ] + }, + { + "id": "38e129d9-e76a-4745-b033-08c4c44493a0", + "name": "roles", + "description": "OpenID Connect scope for add user roles to the access token", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "false", + "display.on.consent.screen": "true", + "consent.screen.text": "${rolesScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "f7f2a4ff-3d7b-4b92-a82d-236cc85d13b3", + "name": "realm roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-realm-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "realm_access.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "c9fd3dea-99d8-4ae2-9ef9-ac4115f3d7cb", + "name": "client roles", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-client-role-mapper", + "consentRequired": false, + "config": { + "user.attribute": "foo", + "access.token.claim": "true", + "claim.name": "resource_access.${client_id}.roles", + "jsonType.label": "String", + "multivalued": "true" + } + }, + { + "id": "9a0a6dae-b105-429a-b119-373094b01654", + "name": "audience resolve", + "protocol": "openid-connect", + "protocolMapper": "oidc-audience-resolve-mapper", + "consentRequired": false, + "config": {} + } + ] + }, + { + "id": "197ed71d-7dd9-4f90-9e38-43feb6b7a1d3", + "name": "role_list", + "description": "SAML role list", + "protocol": "saml", + "attributes": { + "consent.screen.text": "${samlRoleListScopeConsentText}", + "display.on.consent.screen": "true" + }, + "protocolMappers": [ + { + "id": "7056aa7a-b2e4-4b9a-b021-1f702950817e", + "name": "role list", + "protocol": "saml", + "protocolMapper": "saml-role-list-mapper", + "consentRequired": false, + "config": { + "single": "false", + "attribute.nameformat": "Basic", + "attribute.name": "Role" + } + } + ] + }, + { + "id": "895c9d6c-2e12-4885-92d8-b9e4340c2fc8", + "name": "email", + "description": "OpenID Connect built-in scope: email", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${emailScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "4cb1fd27-1c95-4122-931c-305238bb6631", + "name": "email verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "emailVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "a9a962b9-d0d1-467a-9f5a-9b6539a167da", + "name": "email", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "email", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "email", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "9b69f04a-ce75-4434-af66-b268e69eab02", + "name": "profile", + "description": "OpenID Connect built-in scope: profile", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${profileScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "043b295d-c463-419c-9b95-098292342c56", + "name": "username", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "username", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "preferred_username", + "jsonType.label": "String" + } + }, + { + "id": "ce32a84a-eea8-4765-9095-e634caeff35e", + "name": "given name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "firstName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "given_name", + "jsonType.label": "String" + } + }, + { + "id": "9761e952-1660-4940-9265-096f0c44fce4", + "name": "updated at", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "updatedAt", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "updated_at", + "jsonType.label": "String" + } + }, + { + "id": "a77ca8df-72ed-46dc-9522-92c00d34bd2a", + "name": "website", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "website", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "website", + "jsonType.label": "String" + } + }, + { + "id": "23d08775-54c0-41e1-b5b2-c644ca0d5406", + "name": "nickname", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "nickname", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "nickname", + "jsonType.label": "String" + } + }, + { + "id": "aacf881d-72c1-4012-99b8-4681f4b78f7d", + "name": "picture", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "picture", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "picture", + "jsonType.label": "String" + } + }, + { + "id": "238cf4ea-72d8-4572-9a5e-21a5b09ca982", + "name": "family name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-property-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "lastName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "family_name", + "jsonType.label": "String" + } + }, + { + "id": "e422a339-9d40-49b4-b90a-33c9313752f9", + "name": "middle name", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "middleName", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "middle_name", + "jsonType.label": "String" + } + }, + { + "id": "8de3b7b8-e6a8-4ffd-8eaf-7412da9a2cfe", + "name": "gender", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "gender", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "gender", + "jsonType.label": "String" + } + }, + { + "id": "a3913c19-c05d-4430-aad6-e22748347bbd", + "name": "full name", + "protocol": "openid-connect", + "protocolMapper": "oidc-full-name-mapper", + "consentRequired": false, + "config": { + "id.token.claim": "true", + "access.token.claim": "true", + "userinfo.token.claim": "true" + } + }, + { + "id": "2f385018-924e-400a-aa42-6a9d2f03b2d8", + "name": "profile", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "profile", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "profile", + "jsonType.label": "String" + } + }, + { + "id": "d6816d8d-9fcf-48bd-9502-3b02c1641023", + "name": "locale", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "locale", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "locale", + "jsonType.label": "String" + } + }, + { + "id": "5d167c90-0224-4646-830b-9903aa576785", + "name": "birthdate", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "birthdate", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "birthdate", + "jsonType.label": "String" + } + }, + { + "id": "5250b38a-6a91-4565-ab4e-17dbaa5da25a", + "name": "zoneinfo", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "zoneinfo", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "zoneinfo", + "jsonType.label": "String" + } + } + ] + }, + { + "id": "6ca5bc72-8660-4939-9b4c-d6fc1d79850c", + "name": "phone", + "description": "OpenID Connect built-in scope: phone", + "protocol": "openid-connect", + "attributes": { + "include.in.token.scope": "true", + "display.on.consent.screen": "true", + "consent.screen.text": "${phoneScopeConsentText}" + }, + "protocolMappers": [ + { + "id": "17a7cc2b-ea01-4014-adbc-47fb6253f489", + "name": "phone number verified", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumberVerified", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number_verified", + "jsonType.label": "boolean" + } + }, + { + "id": "68939ab7-44e6-468c-85ee-ae954c3c0964", + "name": "phone number", + "protocol": "openid-connect", + "protocolMapper": "oidc-usermodel-attribute-mapper", + "consentRequired": false, + "config": { + "userinfo.token.claim": "true", + "user.attribute": "phoneNumber", + "id.token.claim": "true", + "access.token.claim": "true", + "claim.name": "phone_number", + "jsonType.label": "String" + } + } + ] + } + ], + "defaultDefaultClientScopes": [ + "role_list", + "profile", + "email", + "roles", + "web-origins" + ], + "defaultOptionalClientScopes": [ + "offline_access", + "address", + "phone", + "microprofile-jwt" + ], + "browserSecurityHeaders": { + "contentSecurityPolicyReportOnly": "", + "xContentTypeOptions": "nosniff", + "xRobotsTag": "none", + "xFrameOptions": "SAMEORIGIN", + "contentSecurityPolicy": "frame-src 'self'; frame-ancestors 'self'; object-src 'none';", + "xXSSProtection": "1; mode=block", + "strictTransportSecurity": "max-age=31536000; includeSubDomains" + }, + "smtpServer": {}, + "eventsEnabled": false, + "eventsListeners": [ + "jboss-logging" + ], + "enabledEventTypes": [], + "adminEventsEnabled": false, + "adminEventsDetailsEnabled": false, + "identityProviders": [], + "identityProviderMappers": [], + "components": { + "org.keycloak.services.clientregistration.policy.ClientRegistrationPolicy": [ + { + "id": "30ab0549-ca74-41b1-9d5c-76623f74ed88", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "saml-user-property-mapper", + "oidc-address-mapper", + "oidc-usermodel-property-mapper", + "saml-role-list-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-attribute-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-attribute-mapper" + ] + } + }, + { + "id": "3b84cb11-785f-489c-a62d-d58dcef5c509", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "authenticated", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "732b1bdd-4193-429b-8513-16c3dfffec04", + "name": "Trusted Hosts", + "providerId": "trusted-hosts", + "subType": "anonymous", + "subComponents": {}, + "config": { + "host-sending-registration-request-must-match": [ + "true" + ], + "client-uris-must-match": [ + "true" + ] + } + }, + { + "id": "f8118e08-9941-44b9-84e3-f5f115265bb6", + "name": "Max Clients Limit", + "providerId": "max-clients", + "subType": "anonymous", + "subComponents": {}, + "config": { + "max-clients": [ + "200" + ] + } + }, + { + "id": "56dccbab-5e78-4bc3-b409-d4c822df6d27", + "name": "Consent Required", + "providerId": "consent-required", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "e9e4d9e4-3b37-49ae-827c-87654029a195", + "name": "Full Scope Disabled", + "providerId": "scope", + "subType": "anonymous", + "subComponents": {}, + "config": {} + }, + { + "id": "ade816ce-4776-4b39-8e8b-3238019eda92", + "name": "Allowed Client Scopes", + "providerId": "allowed-client-templates", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allow-default-scopes": [ + "true" + ] + } + }, + { + "id": "943b1440-eb47-4d94-92ba-bb0f7091f54e", + "name": "Allowed Protocol Mapper Types", + "providerId": "allowed-protocol-mappers", + "subType": "anonymous", + "subComponents": {}, + "config": { + "allowed-protocol-mapper-types": [ + "oidc-address-mapper", + "oidc-usermodel-attribute-mapper", + "oidc-sha256-pairwise-sub-mapper", + "saml-user-property-mapper", + "saml-role-list-mapper", + "oidc-full-name-mapper", + "oidc-usermodel-property-mapper", + "saml-user-attribute-mapper" + ] + } + } + ], + "org.keycloak.keys.KeyProvider": [ + { + "id": "f4e2b976-2d72-4155-9f28-1996b516843d", + "name": "rsa-generated", + "providerId": "rsa-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + }, + { + "id": "5b04746f-8b6b-4ae9-a41e-da9eddb2b771", + "name": "hmac-generated", + "providerId": "hmac-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ], + "algorithm": [ + "HS256" + ] + } + }, + { + "id": "2d824490-3399-4c83-8b72-3bfc11008afd", + "name": "aes-generated", + "providerId": "aes-generated", + "subComponents": {}, + "config": { + "priority": [ + "100" + ] + } + } + ] + }, + "internationalizationEnabled": false, + "supportedLocales": [], + "authenticationFlows": [ + { + "id": "9aa67395-f72c-4682-9fdd-231836a7d911", + "alias": "Account verification options", + "description": "Method with which to verity the existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-email-verification", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Verify Existing Account by Re-authentication", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "e6c9bfa0-4948-47f9-8920-b208ac1bc3a5", + "alias": "Authentication Options", + "description": "Authentication options.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "basic-auth", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "basic-auth-otp", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "0c9d5f52-5b10-47bf-b4f2-72170138f86e", + "alias": "Browser - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "842c82d3-38e5-48f4-bbb9-e057e1b0c2ce", + "alias": "Direct Grant - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "a830c1da-97db-4744-8365-8e8096bf59f9", + "alias": "First broker login - Conditional OTP", + "description": "Flow to determine if the OTP is required for the authentication", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-otp-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "aa2850c9-85bd-4229-a307-d8b5ae55412e", + "alias": "Handle Existing Account", + "description": "Handle what to do if there is existing account with same email/username like authenticated identity provider", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-confirm-link", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Account verification options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "e78bf53a-6fad-4cf7-ba00-c2d46b25cea4", + "alias": "Reset - Conditional OTP", + "description": "Flow to determine if the OTP should be reset or not. Set to REQUIRED to force.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "conditional-user-configured", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-otp", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "715df7a1-fba4-4861-8229-b3fd1d80047e", + "alias": "User creation or linking", + "description": "Flow for the existing/non-existing user alternatives", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "create unique user config", + "authenticator": "idp-create-user-if-unique", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 20, + "flowAlias": "Handle Existing Account", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "85d48742-0921-46a7-9abf-dc8acc8021aa", + "alias": "Verify Existing Account by Re-authentication", + "description": "Reauthentication of existing account", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "idp-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "First broker login - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "4512cf14-683b-49f0-81fd-b9a995c44976", + "alias": "browser", + "description": "browser based authentication", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-cookie", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "auth-spnego", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "identity-provider-redirector", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 25, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "ALTERNATIVE", + "priority": 30, + "flowAlias": "forms", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "a73e9d8a-a05c-434d-b8c8-dcda6df1e7ef", + "alias": "clients", + "description": "Base authentication for clients", + "providerId": "client-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "client-secret", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-secret-jwt", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "client-x509", + "authenticatorFlow": false, + "requirement": "ALTERNATIVE", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "ab59950f-fc93-4c14-95f1-2c23c624aca9", + "alias": "direct grant", + "description": "OpenID Connect Resource Owner Grant", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "direct-grant-validate-username", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "direct-grant-validate-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 30, + "flowAlias": "Direct Grant - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "ccf5793b-e6a1-480a-bec8-d9e122053e99", + "alias": "docker auth", + "description": "Used by Docker clients to authenticate against the IDP", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "docker-http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "dd9ffe20-61e8-47b4-b8e1-585ef3eb3d47", + "alias": "first broker login", + "description": "Actions taken after first broker login with identity provider account, which is not yet linked to any Keycloak account", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticatorConfig": "review profile config", + "authenticator": "idp-review-profile", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "User creation or linking", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "d8d78e3d-9a7a-41a8-847b-5ef2d91f5dbd", + "alias": "forms", + "description": "Username, password, otp and other auth forms.", + "providerId": "basic-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "auth-username-password-form", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 20, + "flowAlias": "Browser - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "9755dfd5-f2fe-4695-a010-963dfe8468ab", + "alias": "http challenge", + "description": "An authentication flow based on challenge-response HTTP Authentication Schemes", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "no-cookie-redirect", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 20, + "flowAlias": "Authentication Options", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "066a43ae-2617-4406-9d6a-180e0aa8685f", + "alias": "registration", + "description": "registration flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-page-form", + "authenticatorFlow": true, + "requirement": "REQUIRED", + "priority": 10, + "flowAlias": "registration form", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "84a5aaa7-f510-4a89-96e9-a4541d94bb61", + "alias": "registration form", + "description": "registration form", + "providerId": "form-flow", + "topLevel": false, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "registration-user-creation", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-profile-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 40, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-password-action", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 50, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "registration-recaptcha-action", + "authenticatorFlow": false, + "requirement": "DISABLED", + "priority": 60, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + }, + { + "id": "df945075-5f7b-4917-b70e-0f29552e68ea", + "alias": "reset credentials", + "description": "Reset credentials for a user if they forgot their password or something", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "reset-credentials-choose-user", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-credential-email", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 20, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticator": "reset-password", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 30, + "userSetupAllowed": false, + "autheticatorFlow": false + }, + { + "authenticatorFlow": true, + "requirement": "CONDITIONAL", + "priority": 40, + "flowAlias": "Reset - Conditional OTP", + "userSetupAllowed": false, + "autheticatorFlow": true + } + ] + }, + { + "id": "7fe73f78-24a1-48c7-b714-3d7f48336e30", + "alias": "saml ecp", + "description": "SAML ECP Profile Authentication Flow", + "providerId": "basic-flow", + "topLevel": true, + "builtIn": true, + "authenticationExecutions": [ + { + "authenticator": "http-basic-authenticator", + "authenticatorFlow": false, + "requirement": "REQUIRED", + "priority": 10, + "userSetupAllowed": false, + "autheticatorFlow": false + } + ] + } + ], + "authenticatorConfig": [ + { + "id": "11aba959-54f8-4812-821d-25007b4d8f1c", + "alias": "create unique user config", + "config": { + "require.password.update.after.registration": "false" + } + }, + { + "id": "245f5a86-58a5-4e88-813e-7211d53e9cbc", + "alias": "review profile config", + "config": { + "update.profile.on.first.login": "missing" + } + } + ], + "requiredActions": [ + { + "alias": "CONFIGURE_TOTP", + "name": "Configure OTP", + "providerId": "CONFIGURE_TOTP", + "enabled": true, + "defaultAction": false, + "priority": 10, + "config": {} + }, + { + "alias": "terms_and_conditions", + "name": "Terms and Conditions", + "providerId": "terms_and_conditions", + "enabled": false, + "defaultAction": false, + "priority": 20, + "config": {} + }, + { + "alias": "UPDATE_PASSWORD", + "name": "Update Password", + "providerId": "UPDATE_PASSWORD", + "enabled": true, + "defaultAction": false, + "priority": 30, + "config": {} + }, + { + "alias": "UPDATE_PROFILE", + "name": "Update Profile", + "providerId": "UPDATE_PROFILE", + "enabled": true, + "defaultAction": false, + "priority": 40, + "config": {} + }, + { + "alias": "VERIFY_EMAIL", + "name": "Verify Email", + "providerId": "VERIFY_EMAIL", + "enabled": true, + "defaultAction": false, + "priority": 50, + "config": {} + }, + { + "alias": "delete_account", + "name": "Delete Account", + "providerId": "delete_account", + "enabled": false, + "defaultAction": false, + "priority": 60, + "config": {} + }, + { + "alias": "update_user_locale", + "name": "Update User Locale", + "providerId": "update_user_locale", + "enabled": true, + "defaultAction": false, + "priority": 1000, + "config": {} + } + ], + "browserFlow": "browser", + "registrationFlow": "registration", + "directGrantFlow": "direct grant", + "resetCredentialsFlow": "reset credentials", + "clientAuthenticationFlow": "clients", + "dockerAuthenticationFlow": "docker auth", + "attributes": { + "cibaBackchannelTokenDeliveryMode": "poll", + "cibaExpiresIn": "120", + "cibaAuthRequestedUserHint": "login_hint", + "oauth2DeviceCodeLifespan": "600", + "oauth2DevicePollingInterval": "5", + "clientOfflineSessionMaxLifespan": "0", + "clientSessionIdleTimeout": "0", + "clientSessionMaxLifespan": "0", + "clientOfflineSessionIdleTimeout": "0", + "cibaInterval": "5" + }, + "keycloakVersion": "13.0.1", + "userManagedAccessAllowed": false +} \ No newline at end of file From 20e3ce1eaca45b30b28efb5ad4f03dbc637a7efd Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Wed, 25 Aug 2021 12:41:29 +0530 Subject: [PATCH 11/67] Build config for department entity service (#34) --- build/build-config.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/build/build-config.yml b/build/build-config.yml index a8dadd04..5ca4a1d6 100644 --- a/build/build-config.yml +++ b/build/build-config.yml @@ -36,3 +36,8 @@ config: - work-dir: "core/ifix-zuul" image-name: "ifix-zuul" dockerfile: "build/maven/Dockerfile" + - name: "builds/iFix/domain-services/ifix-department-entity-service" + build: + - work-dir: "domain-services/ifix-department-entity-service" + image-name: "ifix-department-entity-service" + dockerfile: "build/maven/Dockerfile" From f6a32b0687cd34d6b718ca0c4692fa34136ba5a4 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 26 Aug 2021 18:26:44 +0530 Subject: [PATCH 12/67] Convert enum to all caps (#36) Co-authored-by: rushang7-eGov --- .../java/org/egov/web/models/FiscalEvent.java | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java index 0010e1dc..6e6c9ba1 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java @@ -65,15 +65,15 @@ public class FiscalEvent { public enum EventTypeEnum { - Sanction("Sanction"), - Appropriation("Appropriation"), - Allocation("Allocation"), - IntraTransfer("IntraTransfer"), - InterTransfer("InterTransfer"), - Demand("Demand"), - Receipt("Receipt"), - Bill("Bill"), - Payment("Payment"); + SANCTION("SANCTION"), + APPROPRIATION("APPROPRIATION"), + ALLOCATION("ALLOCATION"), + INTRATRANSFER("INTRATRANSFER"), + INTERTRANSFER("INTERTRANSFER"), + DEMAND("DEMAND"), + RECEIPT("RECEIPT"), + BILL("BILL"), + PAYMENT("PAYMENT"); private String value; From 537475b7c0a951e5ae6735ca3b8ec923efcfac05 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Fri, 27 Aug 2021 15:23:25 +0530 Subject: [PATCH 13/67] Rahu 310 (#38) * Supporting code for Project Department Entity Ancestry Integration * Project create API * Enrich department entity ancestry in project. * Added departmentId in DepartmentEntity model * Department entity validation * COA code fix Co-authored-by: rushang7-eGov --- .../MasterDataServiceConfiguration.java | 18 +++ .../egov/repository/ProjectRepository.java | 11 ++ .../ProjectDepartmentEntityIntegration.java | 103 ++++++++++++++++++ .../service/ProjectEnrichmentService.java | 50 +++++++++ .../java/org/egov/service/ProjectService.java | 20 ++++ .../java/org/egov/util/DepartmentUtil.java | 67 ++++++++++++ .../java/org/egov/util/ExpenditureUtil.java | 66 +++++++++++ .../org/egov/util/MasterDataConstants.java | 11 ++ .../main/java/org/egov/util/TenantUtil.java | 67 ++++++++++++ .../org/egov/validator/ProjectValidator.java | 94 ++++++++++++++++ .../web/controllers/ProjectApiController.java | 19 +++- .../org/egov/web/models/DepartmentEntity.java | 33 ++++++ .../models/DepartmentEntityAttributes.java | 26 +++++ .../java/org/egov/web/models/Project.java | 7 +- .../src/main/resources/application.properties | 8 ++ ...20210811131500__chart_of_account_seed_data | 25 +++-- 16 files changed, 611 insertions(+), 14 deletions(-) create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/DepartmentUtil.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/TenantUtil.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntity.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java index 3254833e..4e38b9b0 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java @@ -35,4 +35,22 @@ public void initialize() { @Value("${ifix.master.government.search.path}") private String ifixMasterGovernmentSearchPath; + @Value("${ifix.master.expenditure.host}") + private String ifixMasterExpenditureHost; + + @Value("${ifix.master.expenditure.context.path}") + private String ifixMasterExpenditureContextPath; + + @Value("${ifix.master.expenditure.search.path}") + private String ifixMasterExpenditureSearchPath; + + @Value("${ifix.department.entity.host}") + private String departmentEntityHost; + + @Value("${ifix.department.entity.context.path}") + private String departmentEntityContextPath; + + @Value("${ifix.department.entity.search.path}") + private String departmentEntitySearchPath; + } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java index 933c2ed2..871a867b 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ProjectRepository.java @@ -18,7 +18,18 @@ public class ProjectRepository { @Autowired ProjectQueryBuilder projectQueryBuilder; + /** + * @param projectSearchCriteria + * @return + */ public List findAllByCriteria(ProjectSearchCriteria projectSearchCriteria) { return mongoTemplate.find(projectQueryBuilder.buildQuerySearch(projectSearchCriteria), Project.class); } + + /** + * @param project + */ + public void save(Project project) { + mongoTemplate.save(project); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java new file mode 100644 index 00000000..01410445 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java @@ -0,0 +1,103 @@ +package org.egov.service; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ArrayNode; +import com.fasterxml.jackson.databind.node.ObjectNode; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.DepartmentEntityAttributes; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +@Slf4j +public class ProjectDepartmentEntityIntegration { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private MasterDataServiceConfiguration mdsConfiguration; + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + public DepartmentEntity getDepartmentEntityForId(RequestHeader requestHeader, String tenantId, + String departmentEntityId) { + JsonNode searchRequest = createDepartmentEntitySearchRequest(requestHeader, tenantId, departmentEntityId); + Object response = serviceRequestRepository.fetchResult(createDepartmentEntitySearchUrl(), searchRequest); + JsonNode responseJson = objectMapper.convertValue(response, JsonNode.class); + + JsonNode departmentEntityDetails = responseJson.get("departmentEntity").get(0); + + DepartmentEntity departmentEntity = getCurrentDepartmentEntity(departmentEntityDetails); + departmentEntity.setAncestry(createAncestryArrayFor(departmentEntityDetails)); + + return departmentEntity; + } + + private JsonNode createDepartmentEntitySearchRequest(RequestHeader requestHeader, String tenantId, + String departmentEntityId) { + ArrayNode departmentEntityIds = objectMapper.createArrayNode(); + departmentEntityIds.add(departmentEntityId); + + ObjectNode searchCriteria = objectMapper.createObjectNode(); + searchCriteria.set("Ids", departmentEntityIds); + searchCriteria.put("tenantId", tenantId); + searchCriteria.put("getAncestry", true); + + ObjectNode searchRequest = objectMapper.createObjectNode(); + JsonNode requestHeaderJson = objectMapper.convertValue(requestHeader, JsonNode.class); + searchRequest.set("requestHeader", requestHeaderJson); + searchRequest.set("criteria", searchCriteria); + + return searchRequest; + } + + private DepartmentEntity getCurrentDepartmentEntity(JsonNode departmentEntityDetails) { + while(departmentEntityDetails.get("children").size() != 0) { + departmentEntityDetails = departmentEntityDetails.get("children").get(0); + } + DepartmentEntity departmentEntity = DepartmentEntity.builder() + .id(departmentEntityDetails.get("id").asText()) + .code(departmentEntityDetails.get("code").asText()) + .name(departmentEntityDetails.get("name").asText()) + .hierarchyLevel(departmentEntityDetails.get("hierarchyLevel").asInt()) + .departmentId(departmentEntityDetails.get("departmentId").asText()) + .build(); + return departmentEntity; + } + + private List createAncestryArrayFor(JsonNode departmentEntityDetails) { + List ancestry = new ArrayList<>(); + while (departmentEntityDetails != null) { + DepartmentEntityAttributes departmentEntityAttributes = DepartmentEntityAttributes.builder() + .id(departmentEntityDetails.get("id").asText()) + .code(departmentEntityDetails.get("code").asText()) + .name(departmentEntityDetails.get("name").asText()) + .hierarchyLevel(departmentEntityDetails.get("hierarchyLevel").asInt()) + .build(); + ancestry.add(departmentEntityAttributes); + if(departmentEntityDetails.get("children").size() != 0) + departmentEntityDetails = departmentEntityDetails.get("children").get(0); + else + departmentEntityDetails = null; + } + return ancestry; + } + + private String createDepartmentEntitySearchUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(mdsConfiguration.getDepartmentEntityHost()) + .append(mdsConfiguration.getDepartmentEntityContextPath()) + .append(mdsConfiguration.getDepartmentEntitySearchPath()); + return uriBuilder.toString(); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java new file mode 100644 index 00000000..8e888bc5 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java @@ -0,0 +1,50 @@ +package org.egov.service; + +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.MasterDataServiceUtil; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class ProjectEnrichmentService { + + @Autowired + MasterDataServiceUtil enrichAuditDetails; + @Autowired + private ProjectDepartmentEntityIntegration projectDepartmentEntityIntegration; + + /** + * @param projectRequest + */ + public void enrichProjectData(ProjectRequest projectRequest) { + Project project = projectRequest.getProject(); + addDepartmentEntityDetails(projectRequest); + RequestHeader requestHeader = projectRequest.getRequestHeader(); + + AuditDetails auditDetails = null; + + if(project.getAuditDetails() == null){ + auditDetails = enrichAuditDetails + .enrichAuditDetails(requestHeader.getUserInfo().getUuid(), project.getAuditDetails(), true); + }else{ + auditDetails = enrichAuditDetails + .enrichAuditDetails(requestHeader.getUserInfo().getUuid(), project.getAuditDetails(), false); + } + + project.setId(UUID.randomUUID().toString()); + project.setAuditDetails(auditDetails); + } + + private void addDepartmentEntityDetails(ProjectRequest projectRequest) { + Project project = projectRequest.getProject(); + DepartmentEntity departmentEntity = + projectDepartmentEntityIntegration.getDepartmentEntityForId(projectRequest.getRequestHeader(), + project.getTenantId(), project.getDepartmentEntitytId()); + project.setDepartmentEntity(departmentEntity); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java index c6a04b68..237eb34c 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectService.java @@ -3,6 +3,7 @@ import org.egov.repository.ProjectRepository; import org.egov.validator.ProjectValidator; import org.egov.web.models.Project; +import org.egov.web.models.ProjectRequest; import org.egov.web.models.ProjectSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -18,9 +19,28 @@ public class ProjectService { @Autowired ProjectRepository projectRepository; + @Autowired + ProjectEnrichmentService projectEnrichmentService; + + /** + * @param projectSearchRequest + * @return + */ public List findAllByCriteria(ProjectSearchRequest projectSearchRequest) { projectValidator.validateProjectSearchRequest(projectSearchRequest); return projectRepository.findAllByCriteria(projectSearchRequest.getCriteria()); } + + /** + * @param projectRequest + * @return + */ + public ProjectRequest createProject(ProjectRequest projectRequest) { + projectValidator.validateProjectCreateRequest(projectRequest); + projectEnrichmentService.enrichProjectData(projectRequest); + projectRepository.save(projectRequest.getProject()); + + return projectRequest; + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/DepartmentUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/DepartmentUtil.java new file mode 100644 index 00000000..c6446915 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/DepartmentUtil.java @@ -0,0 +1,67 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class DepartmentUtil { + @Autowired + private MasterDataServiceConfiguration configuration; + + @Autowired + private ServiceRequestRepository searchRequestRepository; + + /** + * @param tenantId + * @param idList + * @param requestHeader + * @return + */ + public boolean validateDepartmentEntity(String tenantId, List idList, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId) && idList != null && !idList.isEmpty()) { + Map departmentEntityValueMap = new HashMap<>(); + departmentEntityValueMap.put(MasterDataConstants.IDS, idList); + departmentEntityValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, tenantId); + departmentEntityValueMap.put(MasterDataConstants.GET_ANCESTRY, false); + + Map departmentEntityMap = new HashMap<>(); + departmentEntityMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + departmentEntityMap.put(MasterDataConstants.CRITERIA, departmentEntityValueMap); + + Object response = searchRequestRepository.fetchResult(createDepartmentEntitySearchUrl(), departmentEntityMap); + + try { + List list = JsonPath.read(response, MasterDataConstants.DEPARTMENT_ENTITY_LIST); + + return list != null && !list.isEmpty(); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse department response"); + } + } + + return false; + } + + /** + * @return + */ + private String createDepartmentEntitySearchUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getDepartmentEntityHost()) + .append(configuration.getDepartmentEntityContextPath()) + .append(configuration.getDepartmentEntitySearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java new file mode 100644 index 00000000..72cc844d --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java @@ -0,0 +1,66 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class ExpenditureUtil { + @Autowired + private MasterDataServiceConfiguration configuration; + + @Autowired + private ServiceRequestRepository searchRequestRepository; + + /** + * @param tenantId + * @param idList + * @param requestHeader + * @return + */ + public boolean validateExpenditure(String tenantId, List idList, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId) && idList != null && !idList.isEmpty()) { + Map expenditureValueMap = new HashMap<>(); + expenditureValueMap.put(MasterDataConstants.IDS, idList); + expenditureValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, tenantId); + + Map expenditureMap = new HashMap<>(); + expenditureMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + expenditureMap.put(MasterDataConstants.CRITERIA, expenditureValueMap); + + Object response = searchRequestRepository.fetchResult(createSearchExpenditureUrl(), expenditureMap); + try { + List list = JsonPath.read(response, MasterDataConstants.EXPENDITURE_LIST); + + return list != null && !list.isEmpty(); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse expenditure response"); + } + } + + return false; + } + + /** + * @return + */ + private String createSearchExpenditureUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getIfixMasterExpenditureHost()) + .append(configuration.getIfixMasterExpenditureContextPath()) + .append(configuration.getIfixMasterExpenditureSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java index 61411fda..ddbc8db2 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -23,6 +23,17 @@ private MasterDataConstants() { public static final String EXPENDITURE_ID = "EXPENDITURE_ID"; public static final String DEPARTMENT_ID = "DEPARTMENT_ID"; public static final String LOCATION_ID = "LOCATION_ID"; + public static final String IDS = "Ids"; + public static final String REQUEST_HEADER = "requestHeader"; + public static final String CRITERIA = "criteria"; + public static final String TENANT_LIST = "$.government.*"; + public static final String EXPENDITURE_LIST = "$.expenditure.*"; + public static final String DEPARTMENT_ENTITY_LIST = "$.departmentEntity.*"; + public static final String DEPARTMENT_ENTITY_ID = "DEPARTMENT_ENTITY_ID"; + + public static final String JSONPATH_ERROR = "JSONPATH_ERROR"; + public static final String GET_ANCESTRY = "getAncestry"; + } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/TenantUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/TenantUtil.java new file mode 100644 index 00000000..ceea4f5b --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/TenantUtil.java @@ -0,0 +1,67 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class TenantUtil { + + @Autowired + private MasterDataServiceConfiguration configuration; + + @Autowired + private ServiceRequestRepository searchRequestRepository; + + /** + * @param tenantId + * @param requestHeader + * @return + */ + public boolean validateTenant(String tenantId, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId)) { + Map tenantValueMap = new HashMap<>(); + tenantValueMap.put(MasterDataConstants.IDS, Collections.singletonList(tenantId.trim())); + + Map tenantMap = new HashMap<>(); + tenantMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + tenantMap.put(MasterDataConstants.CRITERIA, tenantValueMap); + + Object response = searchRequestRepository.fetchResult(createSearchGovernmentUrl(), tenantMap); + try { + List list = JsonPath.read(response, MasterDataConstants.TENANT_LIST); + + return list != null && !list.isEmpty(); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse government " + + "response for tenantId"); + } + } + + return false; + } + + /** + * @return + */ + private String createSearchGovernmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getIfixMasterGovernmentHost()) + .append(configuration.getIfixMasterGovernmentContextPath()) + .append(configuration.getIfixMasterGovernmentSearchPath()); + return uriBuilder.toString(); + } + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java index 7e8be781..b86e9c9b 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java @@ -3,14 +3,37 @@ import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; import org.egov.tracer.model.CustomException; +import org.egov.util.DepartmentUtil; +import org.egov.util.ExpenditureUtil; import org.egov.util.MasterDataConstants; +import org.egov.util.TenantUtil; +import org.egov.web.models.Project; +import org.egov.web.models.ProjectRequest; import org.egov.web.models.ProjectSearchCriteria; import org.egov.web.models.ProjectSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @Component public class ProjectValidator { + @Autowired + private TenantUtil tenantUtil; + + @Autowired + private ExpenditureUtil expenditureUtil; + + @Autowired + private DepartmentUtil departmentUtil; + + /** + * @param projectSearchRequest + */ public void validateProjectSearchRequest(ProjectSearchRequest projectSearchRequest) { if (projectSearchRequest != null && projectSearchRequest.getRequestHeader() != null && projectSearchRequest.getCriteria() != null) { @@ -67,4 +90,75 @@ public void validateProjectSearchRequest(ProjectSearchRequest projectSearchReque } } } + + /** + * @param projectRequest + */ + public void validateProjectCreateRequest(ProjectRequest projectRequest) { + Map errorMap = new HashMap<>(); + + if (projectRequest != null && projectRequest.getProject() != null && projectRequest.getRequestHeader() != null) { + RequestHeader requestHeader = projectRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + errorMap.put(MasterDataConstants.USER_INFO, "User information is missing"); + } + + Project project = projectRequest.getProject(); + + if (StringUtils.isEmpty(project.getTenantId())) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); + }else if (project.getTenantId().length() < 2 || project.getTenantId().length() > 64) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + }else if (!tenantUtil.validateTenant(project.getTenantId(),requestHeader)) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id : " + project.getTenantId() + + " doesn't exist in the system"); + } + + if (StringUtils.isEmpty(project.getCode())) { + errorMap.put(MasterDataConstants.PROJECT_CODE, "Project code is missing in request data"); + }else if (project.getCode().length() < 1 || project.getCode().length() > 64) { + errorMap.put(MasterDataConstants.PROJECT_CODE, "Project code length is invalid. Length range [1-64]"); + } + + if (StringUtils.isEmpty(project.getName())) { + errorMap.put(MasterDataConstants.PROJECT_NAME, "Project name is missing in request data"); + }else if (project.getName().length() < 1 || project.getName().length() > 64) { + errorMap.put(MasterDataConstants.PROJECT_NAME, "Project name length is invalid. Length range [1-64]"); + } + + if (!StringUtils.isEmpty(project.getExpenditureId())) { + if (project.getExpenditureId().length() < 2 || project.getExpenditureId().length() > 64) { + errorMap.put(MasterDataConstants.EXPENDITURE_ID, "Expenditure id length is invalid. Length range [2-64]"); + } + + if (!expenditureUtil.validateExpenditure(project.getTenantId(), + Collections.singletonList(project.getExpenditureId()), requestHeader)) { + errorMap.put(MasterDataConstants.EXPENDITURE_ID, "Expenditure id : " + project.getExpenditureId() + + " doesn't exist in the system"); + } + } + + if (!StringUtils.isEmpty(project.getDepartmentEntitytId())) { + if (project.getDepartmentEntitytId().length() < 2 || project.getDepartmentEntitytId().length() > 64) { + errorMap.put(MasterDataConstants.DEPARTMENT_ENTITY_ID, "Department Entity id length is invalid. " + + "Length range [2-64]"); + } + + if (!departmentUtil.validateDepartmentEntity(project.getTenantId(), + Collections.singletonList(project.getDepartmentEntitytId()), requestHeader)) { + errorMap.put(MasterDataConstants.DEPARTMENT_ENTITY_ID, "Department Entity id : " + + project.getExpenditureId() + " doesn't exist in the system"); + } + } + + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + }else { + throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, + "Request payload is missing some value"); + } + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java index f2336153..fe87aea0 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java @@ -19,6 +19,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.io.IOException; +import java.util.Collections; import java.util.List; @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") @@ -43,13 +44,29 @@ public ProjectApiController(ObjectMapper objectMapper, HttpServletRequest reques this.request = request; } + /** + * @param body + * @return + */ @RequestMapping(value = "/_create", method = RequestMethod.POST) public ResponseEntity projectV1CreatePost(@ApiParam(value = "Details for the new Project " + "RequestHeader (meta data of the API).", required = true) @Valid @RequestBody ProjectRequest body) { - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + ProjectRequest projectRequest = projectService.createProject(body); + + ResponseHeader responseHeader = responseHeaderCreator + .createResponseHeaderFromRequestHeader(body.getRequestHeader(),true); + + ProjectResponse projectResponse = ProjectResponse.builder().responseHeader(responseHeader) + .project(Collections.singletonList(projectRequest.getProject())).build(); + + return new ResponseEntity<>(projectResponse, HttpStatus.OK); } + /** + * @param body + * @return + */ @RequestMapping(value = "/_search", method = RequestMethod.POST) public ResponseEntity projectV1SearchPost(@ApiParam(value = "Details for the Project search " + "criteria RequestHeader (meta data of the API).", required = true) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntity.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntity.java new file mode 100644 index 00000000..ee35d324 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntity.java @@ -0,0 +1,33 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntity { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("departmentId") + private String departmentId; + + @JsonProperty("hierarchyLevel") + private Integer hierarchyLevel = null; + + @JsonProperty("ancestry") + private List ancestry; + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java new file mode 100644 index 00000000..2336a503 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java @@ -0,0 +1,26 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; +import org.egov.common.contract.AuditDetails; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntityAttributes { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("hierarchyLevel") + private Integer hierarchyLevel = null; + +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java index 76777054..0c52deb2 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Project.java @@ -38,8 +38,11 @@ public class Project { @JsonProperty("expenditureId") private String expenditureId = null; - @JsonProperty("departmentId") - private String departmentId = null; + @JsonProperty("departmentEntitytId") + private String departmentEntitytId = null; + + @JsonProperty("departmentEntity") + private DepartmentEntity departmentEntity = null; @JsonProperty("locationIds") @Valid diff --git a/domain-services/ifix-master-data-service/src/main/resources/application.properties b/domain-services/ifix-master-data-service/src/main/resources/application.properties index fed6a7f3..bb83f67c 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/application.properties +++ b/domain-services/ifix-master-data-service/src/main/resources/application.properties @@ -12,3 +12,11 @@ spring.data.mongodb.database=ifix_dev_db ifix.master.government.host=http://localhost:8030 ifix.master.government.context.path=/ifix-master-data ifix.master.government.search.path=/government/v1/_search + +ifix.master.expenditure.host=http://localhost:8030 +ifix.master.expenditure.context.path=/ifix-master-data +ifix.master.expenditure.search.path=/expenditure/v1/_search + +ifix.department.entity.host=http://localhost:8032 +ifix.department.entity.context.path=/ifix-department-entity +ifix.department.entity.search.path=/departmentEntity/v1/_search diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data index fa61066a..b60daf0c 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data +++ b/domain-services/ifix-master-data-service/src/main/resources/db/seed/V20210811131500__chart_of_account_seed_data @@ -2,6 +2,7 @@ db.chartOfAccount.insertMany([ { "_id": "50cc5634-6cc3-456b-ae33-e40741128cdc", "tenantId": "pb", + "coaCode": "8243-12-373-56-78-90", "majorHead": "8243", "majorHeadName": "majorHeadName82", "majorHeadtype": "majorHeadtype", @@ -26,18 +27,19 @@ db.chartOfAccount.insertMany([ { "_id": "50cc5634-6cc3-456b-ae33-e40741128cde", "tenantId": "pb", - "majorHead": "8243", + "coaCode": "8244-13-374-57-79-91", + "majorHead": "8244", "majorHeadName": "majorHeadName82", "majorHeadtype": "majorHeadtype", - "subMajorHead": "12", + "subMajorHead": "13", "subMajorHeadName": "subMajorHeadName", - "minorHead": "373", + "minorHead": "374", "minorHeadName": "minorHeadName347", - "subHead": "56", + "subHead": "57", "subHeadName": "subHeadName", - "groupHead": "78", + "groupHead": "79", "groupHeadName": "groupHeadName", - "objectHead": "90", + "objectHead": "91", "objectHeadName": "objectHeadName", "auditDetails" : { "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", @@ -50,18 +52,19 @@ db.chartOfAccount.insertMany([ { "_id": "50cc5634-6cc3-456b-ae33-e40741128cd3", "tenantId": "pb", - "majorHead": "8943", + "coaCode": "8245-14-567-58-80-92", + "majorHead": "8945", "majorHeadName": "majorHeadName89", "majorHeadtype": "majorHeadtype", - "subMajorHead": "12", + "subMajorHead": "14", "subMajorHeadName": "subMajorHeadName", "minorHead": "567", "minorHeadName": "minorHeadName347", - "subHead": "56", + "subHead": "58", "subHeadName": "subHeadName", - "groupHead": "78", + "groupHead": "80", "groupHeadName": "groupHeadName", - "objectHead": "90", + "objectHead": "92", "objectHeadName": "objectHeadName", "auditDetails" : { "createdBy" : "e4fd96e8-3b6b-4e36-9503-0f14a01af39d", From 49e6f85c5cd5928c7b4c0f80972ae5bf777b9c1a Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Fri, 27 Aug 2021 16:40:06 +0530 Subject: [PATCH 14/67] Refactored: responseInfo -> responseHeader (#39) --- .../java/org/egov/web/controllers/FiscalApiController.java | 2 +- .../main/java/org/egov/web/models/FiscalEventResponse.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java index a93b6cf2..9a2f1480 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java @@ -47,7 +47,7 @@ public FiscalApiController(ObjectMapper objectMapper, HttpServletRequest request public ResponseEntity fiscalEventsV1PushPost(@ApiParam(value = "Details for the new fiscal event + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody FiscalEventRequest body) { FiscalEventRequest fiscalEventRequest = fiscalEventService.fiscalEventsV1PushPost(body); ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); - FiscalEventResponse fiscalEventResponse = FiscalEventResponse.builder().responseInfo(responseHeader) + FiscalEventResponse fiscalEventResponse = FiscalEventResponse.builder().responseHeader(responseHeader) .fiscalEvent(Collections.singletonList(fiscalEventRequest.getFiscalEvent())).build(); return new ResponseEntity(fiscalEventResponse, HttpStatus.ACCEPTED); } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java index 6a34f79a..ebcc22fe 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEventResponse.java @@ -23,8 +23,8 @@ @NoArgsConstructor @Builder public class FiscalEventResponse { - @JsonProperty("responseInfo") - private ResponseHeader responseInfo = null; + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; @JsonProperty("fiscalEvent") @Valid From 179f2da6d9fa44094db5324b44d9e6e2b4c26831 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Fri, 27 Aug 2021 17:08:24 +0530 Subject: [PATCH 15/67] Pk department entity post processor (#40) --- .../druid-ingestion-config.json | 43 +++++++++++++++-- .../FiscalEventDereferenceService.java | 47 ++++++++++++++----- .../service/FiscalEventUnbundleService.java | 1 + .../org/egov/util/MasterDataConstants.java | 2 +- .../main/java/org/egov/util/ProjectUtil.java | 34 ++++++++++---- .../org/egov/web/models/DepartmentEntity.java | 30 ++++++++++++ .../models/DepartmentEntityAttributes.java | 25 ++++++++++ .../java/org/egov/web/models/FiscalEvent.java | 18 +++---- .../web/models/FiscalEventDeReferenced.java | 3 ++ .../models/FiscalEventLineItemUnbundled.java | 3 ++ .../java/org/egov/web/models/Project.java | 9 ++-- 11 files changed, 175 insertions(+), 40 deletions(-) create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntity.java create mode 100644 domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java diff --git a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json index 2832dbcc..fbb4aca1 100644 --- a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json +++ b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json @@ -61,6 +61,45 @@ "department.code", "department.id", "department.name", + + "departmentEntity.code", + "departmentEntity.name", + "departmentEntity.hierarchyLevel", + + "departmentEntity.ancestry[0].code", + "departmentEntity.ancestry[0].name", + "departmentEntity.ancestry[0].hierarchyLevel", + "departmentEntity.ancestry[1].code", + "departmentEntity.ancestry[1].name", + "departmentEntity.ancestry[1].hierarchyLevel", + "departmentEntity.ancestry[2].code", + "departmentEntity.ancestry[2].name", + "departmentEntity.ancestry[2].hierarchyLevel", + "departmentEntity.ancestry[3].code", + "departmentEntity.ancestry[3].name", + "departmentEntity.ancestry[3].hierarchyLevel", + "departmentEntity.ancestry[4].code", + "departmentEntity.ancestry[4].name", + "departmentEntity.ancestry[4].hierarchyLevel", + "departmentEntity.ancestry[5].code", + "departmentEntity.ancestry[5].name", + "departmentEntity.ancestry[5].hierarchyLevel", + "departmentEntity.ancestry[6].code", + "departmentEntity.ancestry[6].name", + "departmentEntity.ancestry[6].hierarchyLevel", + "departmentEntity.ancestry[7].code", + "departmentEntity.ancestry[7].name", + "departmentEntity.ancestry[7].hierarchyLevel", + "departmentEntity.ancestry[8].code", + "departmentEntity.ancestry[8].name", + "departmentEntity.ancestry[8].hierarchyLevel", + "departmentEntity.ancestry[9].code", + "departmentEntity.ancestry[9].name", + "departmentEntity.ancestry[9].hierarchyLevel", + "departmentEntity.ancestry[10].code", + "departmentEntity.ancestry[10].name", + "departmentEntity.ancestry[10].hierarchyLevel", + "eventId", { "type": "long", @@ -83,10 +122,8 @@ "id", "parentEventId", "parentReferenceId", - "project.code", - "project.departmentId", - "project.expenditureId", "project.id", + "project.code", "project.name", "referenceId", "tenantId", diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java index 79a22ae9..34e659af 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java @@ -1,10 +1,9 @@ package org.egov.service; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.egov.config.FiscalEventPostProcessorConfig; -import org.egov.producer.Producer; import org.egov.util.*; import org.egov.web.models.*; import org.springframework.beans.BeanUtils; @@ -12,7 +11,9 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map; @Service @Slf4j @@ -104,21 +105,39 @@ private void dereferenceCoaId(FiscalEventRequest fiscalEventRequest, FiscalEvent */ private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { if (isValidProjectIdParam(fiscalEventRequest) && fiscalEventDeReferenced != null) { - List projectList = projectUtil.getProjectReference(fiscalEventRequest); - if (projectList != null && !projectList.isEmpty()) { - Project project = projectList.get(0); - fiscalEventDeReferenced.setProject(project); + JsonNode jsonNode = projectUtil.getProjectReference(fiscalEventRequest); + JsonNode projectListNode = jsonNode.get("project"); + if (projectListNode != null && !projectListNode.isEmpty()) { + JsonNode projectNode = projectListNode.get(0); + + String expenditureId = null; + String departmentId = null; + if(projectNode != null && !projectNode.isEmpty()) { + expenditureId = projectNode.get("expenditureId").asText(); + departmentId = projectNode.get("departmentEntity").get("departmentId").asText(); + + fiscalEventDeReferenced.setProject(getProjectDetails(projectNode)); + fiscalEventDeReferenced.setDepartmentEntity(projectUtil.getDepartmentEntityFromProject(projectNode.get("departmentEntity"))); + } + + List expenditureList = null; + if (StringUtils.isNotBlank(expenditureId)) { + expenditureList = expenditureUtil.getExpenditureReference(fiscalEventRequest.getFiscalEvent().getTenantId(), + expenditureId, fiscalEventRequest.getRequestHeader()); + } - List expenditureList = expenditureUtil.getExpenditureReference(fiscalEventRequest.getFiscalEvent().getTenantId(), - project.getExpenditureId(), fiscalEventRequest.getRequestHeader()); if (expenditureList != null && !expenditureList.isEmpty()) { fiscalEventDeReferenced.setExpenditure(expenditureList.get(0)); } - List departmentList = departmentUtil - .getDepartmentReference(fiscalEventRequest.getFiscalEvent().getTenantId(), - project.getDepartmentId(), fiscalEventRequest.getRequestHeader()); + List departmentList = null; + if (StringUtils.isNotBlank(departmentId)) { + departmentList = departmentUtil + .getDepartmentReference(fiscalEventRequest.getFiscalEvent().getTenantId(), + departmentId, fiscalEventRequest.getRequestHeader()); + } + if (departmentList != null && !departmentList.isEmpty()) { fiscalEventDeReferenced.setDepartment(departmentList.get(0)); } @@ -126,6 +145,12 @@ private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalE } } + private Project getProjectDetails(JsonNode projectNode) { + return Project.builder().id(projectNode.get("id").asText()) + .code(projectNode.get("code").asText()) + .name(projectNode.get("name").asText()).build(); + } + /** * @param fiscalEventRequest * @return diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java index 77c877e5..0daef5d2 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java @@ -62,6 +62,7 @@ private FiscalEventLineItemUnbundled getUnbundleFiscalEventFromDereferenceEvent( fiscalEventLineItemUnbundled.setReferenceId(fiscalEventDeReferenced.getReferenceId()); fiscalEventLineItemUnbundled.setTenantId(fiscalEventDeReferenced.getTenantId()); fiscalEventLineItemUnbundled.setVersion(fiscalEventDeReferenced.getVersion()); + fiscalEventLineItemUnbundled.setDepartmentEntity(fiscalEventDeReferenced.getDepartmentEntity()); return fiscalEventLineItemUnbundled; } } diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java index 4f3f394f..5a886729 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/MasterDataConstants.java @@ -6,7 +6,7 @@ public class MasterDataConstants { public static final String FISCAL_EVENT = "FISCAL_EVENT"; public static final String REFERENCE_ID = "REFERENCE_ID"; public static final String EVENT_TYPE = "EVENT_TYPE"; - public static final String FISCAL_EVENT_VERSION = "0.0.2"; + public static final String FISCAL_EVENT_VERSION = "0.0.3"; private MasterDataConstants() { } diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java index 373159dd..078c8f82 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java @@ -1,6 +1,8 @@ package org.egov.util; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import lombok.extern.slf4j.Slf4j; @@ -8,6 +10,7 @@ import org.egov.config.FiscalEventPostProcessorConfig; import org.egov.resposioty.ServiceRequestRepository; import org.egov.tracer.model.CustomException; +import org.egov.web.models.DepartmentEntity; import org.egov.web.models.FiscalEventRequest; import org.egov.web.models.Project; import org.springframework.beans.factory.annotation.Autowired; @@ -32,9 +35,10 @@ public class ProjectUtil { /** * @param fiscalEventRequest + * @param idMap * @return */ - public List getProjectReference(FiscalEventRequest fiscalEventRequest) { + public JsonNode getProjectReference(FiscalEventRequest fiscalEventRequest) { if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null && fiscalEventRequest.getFiscalEvent() != null && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getProjectId())) { @@ -50,16 +54,10 @@ public List getProjectReference(FiscalEventRequest fiscalEventRequest) ProjectMap.put(MasterDataConstants.CRITERIA, projectValueMap); Object response = serviceRequestRepository.fetchResult(createSearchProjectUrl(), ProjectMap); - - try{ - List projectList = JsonPath.read(response, MasterDataConstants.PROJECT_LIST); - - return objectMapper.convertValue(projectList, new TypeReference>() {}); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); - } + JsonNode jsonNode = objectMapper.convertValue(response, JsonNode.class); + return jsonNode; } - return Collections.emptyList(); + return objectMapper.createObjectNode(); } private String createSearchProjectUrl() { @@ -69,4 +67,20 @@ private String createSearchProjectUrl() { .append(processorConfig.getIfixMasterProjectSearchPath()); return uriBuilder.toString(); } + + /** + * + * @param departmentEntityNode + * @return + */ + public DepartmentEntity getDepartmentEntityFromProject(JsonNode departmentEntityNode) { + DepartmentEntity departmentEntity = null; + try { + departmentEntity = objectMapper.treeToValue(departmentEntityNode, DepartmentEntity.class); + } catch (JsonProcessingException e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse project Node for department entity"); + } + return departmentEntity; + } } + diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntity.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntity.java new file mode 100644 index 00000000..2932806c --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntity.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +import java.util.List; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntity { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("hierarchyLevel") + private Integer hierarchyLevel = null; + + @JsonProperty("ancestry") + private List ancestry; + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java new file mode 100644 index 00000000..88d93eb3 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java @@ -0,0 +1,25 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.*; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntityAttributes { + + @JsonProperty("id") + private String id = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("hierarchyLevel") + private Integer hierarchyLevel = null; + +} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java index 7fa2395d..ba18053e 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java @@ -67,15 +67,15 @@ public class FiscalEvent { public enum EventTypeEnum { - Sanction("Sanction"), - Appropriation("Appropriation"), - Allocation("Allocation"), - IntraTransfer("IntraTransfer"), - InterTransfer("InterTransfer"), - Demand("Demand"), - Receipt("Receipt"), - Bill("Bill"), - Payment("Payment"); + SANCTION("SANCTION"), + APPROPRIATION("APPROPRIATION"), + ALLOCATION("ALLOCATION"), + INTRA_TRANSFER("INTRA_TRANSFER"), + INTER_TRANSFER("INTER_TRANSFER"), + DEMAND("DEMAND"), + RECEIPT("RECEIPT"), + BILL("BILL"), + PAYMENT("PAYMENT"); private String value; diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java index d1e1d822..f80a17e7 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDeReferenced.java @@ -39,6 +39,9 @@ public class FiscalEventDeReferenced { @JsonProperty("department") private Department department = null; + @JsonProperty("departmentEntity") + private DepartmentEntity departmentEntity = null; + @JsonProperty("expenditure") private Expenditure expenditure = null; diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java index 6660e9d6..0b6f1fa9 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventLineItemUnbundled.java @@ -39,6 +39,9 @@ public class FiscalEventLineItemUnbundled { @JsonProperty("department") private Department department = null; + @JsonProperty("departmentEntity") + private DepartmentEntity departmentEntity = null; + @JsonProperty("expenditure") private Expenditure expenditure = null; diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java index 1e558842..8caecdde 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java @@ -26,12 +26,9 @@ public class Project { @JsonProperty("name") private String name = null; - - @JsonProperty("expenditureId") - private String expenditureId = null; - - @JsonProperty("departmentId") - private String departmentId = null; +// +// @JsonProperty("departmentEntity") +// private DepartmentEntity departmentEntity = null; } From 544d7d74afe80f6873ce591c50af1e3f93e0112b Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Mon, 30 Aug 2021 11:07:48 +0530 Subject: [PATCH 16/67] Updated Druid ingestion config (#41) Co-authored-by: rushang7-eGov --- .../druid-ingestion-config.json | 91 +++++++++---------- 1 file changed, 45 insertions(+), 46 deletions(-) diff --git a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json index fbb4aca1..66b0eebe 100644 --- a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json +++ b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json @@ -23,115 +23,114 @@ }, "dimensionsSpec": { "dimensions": [ + "id", { "type": "double", "name": "amount" }, + + "version", + "tenantId", + "eventId", { "type": "long", - "name": "coa.groupHead" + "name": "eventTime" }, - "coa.groupHeadName", - "coa.id", + "eventType", + "referenceId", + "parentEventId", + "parentReferenceId", + { "type": "long", - "name": "coa.majorHead" + "name": "fromBillingPeriod" }, - "coa.majorHeadName", { "type": "long", - "name": "coa.minorHead" + "name": "toBillingPeriod" }, + + "coa.id", + "coa.coaCode", + "coa.majorHead", + "coa.majorHeadName", + "coa.subMajorHead", + "coa.subMajorHeadName", + "coa.minorHead", "coa.minorHeadName", - { - "type": "long", - "name": "coa.objectHead" - }, - "coa.objectHeadName", - { - "type": "long", - "name": "coa.subHead" - }, + "coa.subHead", "coa.subHeadName", - { - "type": "long", - "name": "coa.subMajorHead" - }, - "coa.subMajorHeadName", - "department.code", + "coa.groupHead", + "coa.groupHeadName", + "coa.objectHead", + "coa.objectHeadName", + "department.id", + "department.code", "department.name", + "departmentEntity.id", "departmentEntity.code", "departmentEntity.name", "departmentEntity.hierarchyLevel", + "departmentEntity.ancestry[0].id", "departmentEntity.ancestry[0].code", "departmentEntity.ancestry[0].name", "departmentEntity.ancestry[0].hierarchyLevel", + "departmentEntity.ancestry[1].id", "departmentEntity.ancestry[1].code", "departmentEntity.ancestry[1].name", "departmentEntity.ancestry[1].hierarchyLevel", + "departmentEntity.ancestry[2].id", "departmentEntity.ancestry[2].code", "departmentEntity.ancestry[2].name", "departmentEntity.ancestry[2].hierarchyLevel", + "departmentEntity.ancestry[3].id", "departmentEntity.ancestry[3].code", "departmentEntity.ancestry[3].name", "departmentEntity.ancestry[3].hierarchyLevel", + "departmentEntity.ancestry[4].id", "departmentEntity.ancestry[4].code", "departmentEntity.ancestry[4].name", "departmentEntity.ancestry[4].hierarchyLevel", + "departmentEntity.ancestry[5].id", "departmentEntity.ancestry[5].code", "departmentEntity.ancestry[5].name", "departmentEntity.ancestry[5].hierarchyLevel", + "departmentEntity.ancestry[6].id", "departmentEntity.ancestry[6].code", "departmentEntity.ancestry[6].name", "departmentEntity.ancestry[6].hierarchyLevel", + "departmentEntity.ancestry[7].id", "departmentEntity.ancestry[7].code", "departmentEntity.ancestry[7].name", "departmentEntity.ancestry[7].hierarchyLevel", + "departmentEntity.ancestry[8].id", "departmentEntity.ancestry[8].code", "departmentEntity.ancestry[8].name", "departmentEntity.ancestry[8].hierarchyLevel", + "departmentEntity.ancestry[9].id", "departmentEntity.ancestry[9].code", "departmentEntity.ancestry[9].name", "departmentEntity.ancestry[9].hierarchyLevel", + "departmentEntity.ancestry[10].id", "departmentEntity.ancestry[10].code", "departmentEntity.ancestry[10].name", "departmentEntity.ancestry[10].hierarchyLevel", - "eventId", - { - "type": "long", - "name": "eventTime" - }, - "eventType", - { - "type": "long", - "name": "expenditure.code" - }, "expenditure.id", + "expenditure.code", "expenditure.name", "expenditure.type", - { - "type": "long", - "name": "fromBillingPeriod" - }, + "government.id", "government.name", - "id", - "parentEventId", - "parentReferenceId", + "project.id", "project.code", - "project.name", - "referenceId", - "tenantId", - { - "type": "long", - "name": "toBillingPeriod" - }, - "version" + "project.name" + ] }, "granularitySpec": { From 41dabb7711bb65cab561c46d54aa6551d47f8d29 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:29:47 +0530 Subject: [PATCH 17/67] IFIX-320: EAT index refactor (#44) --- .../resources/db/migration/V20210811131300__create_index | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index index 289ec199..c470f94e 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index +++ b/domain-services/ifix-master-data-service/src/main/resources/db/migration/V20210811131300__create_index @@ -13,12 +13,12 @@ db.chartOfAccount.createIndexes( ); db.chartOfAccount.getIndexes(); -db.eAT.createIndexes( +db.expenditure.createIndexes( [{"name":1},{"code":1},{"tenantId":1}] ); -db.eAT.getIndexes(); +db.expenditure.getIndexes(); db.project.createIndexes( - [{"name":1},{"code":1},{"tenantId":1},{"eatId":1},{"departmentId":1},{"locationIds":1}] + [{"name":1},{"code":1},{"tenantId":1},{"expenditureId":1},{"departmentId":1}] ); db.project.getIndexes(); \ No newline at end of file From 27b0de0f2a2b141c7f56f3515d955757d6da2ab3 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 31 Aug 2021 15:33:16 +0530 Subject: [PATCH 18/67] Ifix department entity service (#45) * Update build-config.yml (#3) * Update build-config.yml (#4) * Update build-config.yml (#5) * Updated Dockerfile base image (#6) * Update build-config.yml (#12) * Update CODEOWNERS * Initial Commit * initial Department entity service setup * initial Department entity service setup * Added build config for ifix-department-entity-service (#26) * Updated context path and port number * Rahu 313 (#27) * IFIX-311: Create Department Hierarchy * Merge branch 'ifix-department-entity-service' of https://github.com/egovernments/iFix-Dev into pk-ifix-department-entity-service # Conflicts: # domain-services/ifix-department-entity-service/src/main/resources/application.properties * IFIX-313: Department entity create api * changed the level data tpe to Integer * DepartmentEntity attribute correction * refactor the GovernmentUtil and DepartmentUtil * DepartmentEntity validation fix Co-authored-by: pintu-eGov * removed unused object, imports * Initialise create index file * Pk ifix department entity service (#32) * IFIX-311: Create Department Hierarchy * Merge branch 'ifix-department-entity-service' of https://github.com/egovernments/iFix-Dev into pk-ifix-department-entity-service # Conflicts: # domain-services/ifix-department-entity-service/src/main/resources/application.properties * IFIX-313: Department entity create api * changed the level data tpe to Integer * IFIX-314: Search Department Hierarchy Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov * Department entity get parent (#33) * Department Entity get parent. * Return complete ancestry. * Added seed data. * Pk ifix department entity service (#35) * IFIX-311: Create Department Hierarchy * Merge branch 'ifix-department-entity-service' of https://github.com/egovernments/iFix-Dev into pk-ifix-department-entity-service # Conflicts: # domain-services/ifix-department-entity-service/src/main/resources/application.properties * IFIX-313: Department entity create api * changed the level data tpe to Integer * IFIX-314: Search Department Hierarchy * IFIX-314: Search Department Entity * Migration scripts * Migration scripts Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov * seed data change and department ancestry attribute correction * Updated seed data Co-authored-by: rushang7-eGov Co-authored-by: nikesh-eGov <48427967+nikesh-eGov@users.noreply.github.com> Co-authored-by: pintu-eGov Co-authored-by: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> --- .../ifix-department-entity-service/.gitignore | 42 +++++ .../ifix-department-entity-service/README.md | 1 + .../ifix-department-entity-service/pom.xml | 100 ++++++++++++ .../src/main/java/org/egov/Main.java | 17 ++ .../config/IfixDepartmentEntityConfig.java | 62 ++++++++ .../org/egov/config/MainConfiguration.java | 39 +++++ .../DepartmentEntityRepository.java | 48 ++++++ .../DepartmentHierarchyLevelRepository.java | 33 ++++ .../repository/ServiceRequestRepository.java | 48 ++++++ .../DepartmentEntityQueryBuilder.java | 35 +++++ .../DepartmentHierarchyLevelQueryBuilder.java | 33 ++++ .../DepartmentEntityEnrichmentService.java | 36 +++++ .../egov/service/DepartmentEntityService.java | 81 ++++++++++ ...rtmentHierarchyLevelEnrichmentService.java | 70 +++++++++ .../DepartmentHierarchyLevelService.java | 70 +++++++++ .../util/DepartmentEntityAncestryUtil.java | 30 ++++ .../egov/util/DepartmentEntityConstant.java | 32 ++++ .../org/egov/util/DepartmentEntityUtil.java | 28 ++++ .../java/org/egov/util/DepartmentUtil.java | 67 ++++++++ .../java/org/egov/util/GovernmentUtil.java | 67 ++++++++ .../org/egov/util/ResponseHeaderCreator.java | 26 ++++ .../validator/DepartmentEntityValidator.java | 92 +++++++++++ .../DepartmentHierarchyLevelValidator.java | 107 +++++++++++++ .../DepartmentEntityApiController.java | 86 +++++++++++ ...DepartmentHierarchyLevelApiController.java | 63 ++++++++ .../org/egov/web/models/DepartmentEntity.java | 37 +++++ .../web/models/DepartmentEntityAbstract.java | 47 ++++++ .../web/models/DepartmentEntityAncestry.java | 37 +++++ .../web/models/DepartmentEntityRequest.java | 30 ++++ .../web/models/DepartmentEntityResponse.java | 42 +++++ .../DepartmentEntitySearchCriteria.java | 57 +++++++ .../models/DepartmentEntitySearchRequest.java | 30 ++++ .../web/models/DepartmentHierarchyLevel.java | 47 ++++++ .../DepartmentHierarchyLevelRequest.java | 30 ++++ .../DepartmentHierarchyLevelResponse.java | 43 ++++++ ...epartmentHierarchyLevelSearchCriteria.java | 52 +++++++ ...DepartmentHierarchyLevelSearchRequest.java | 30 ++++ .../src/main/resources/application.properties | 19 +++ .../migration/V20210824122400__create_index | 10 ++ ...0824192300__department_hierarchy_seed_data | 107 +++++++++++++ ...0210824192400__department_entity_seed_data | 146 ++++++++++++++++++ .../test/java/org/egov/TestConfiguration.java | 16 ++ .../DepartmentEntityApiControllerTest.java | 85 ++++++++++ 43 files changed, 2178 insertions(+) create mode 100644 domain-services/ifix-department-entity-service/.gitignore create mode 100644 domain-services/ifix-department-entity-service/README.md create mode 100644 domain-services/ifix-department-entity-service/pom.xml create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/Main.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/config/IfixDepartmentEntityConfig.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/config/MainConfiguration.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/ServiceRequestRepository.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelService.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityRequest.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchCriteria.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchRequest.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelRequest.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelResponse.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchRequest.java create mode 100644 domain-services/ifix-department-entity-service/src/main/resources/application.properties create mode 100644 domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index create mode 100644 domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192300__department_hierarchy_seed_data create mode 100644 domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192400__department_entity_seed_data create mode 100644 domain-services/ifix-department-entity-service/src/test/java/org/egov/TestConfiguration.java create mode 100644 domain-services/ifix-department-entity-service/src/test/java/org/egov/web/controllers/DepartmentEntityApiControllerTest.java diff --git a/domain-services/ifix-department-entity-service/.gitignore b/domain-services/ifix-department-entity-service/.gitignore new file mode 100644 index 00000000..6edbdcda --- /dev/null +++ b/domain-services/ifix-department-entity-service/.gitignore @@ -0,0 +1,42 @@ +*# +*.iml +*.ipr +*.iws +*.jar +*.sw? +*~ +.#* +.*.md.html +.DS_Store +.attach_pid* +.classpath +.factorypath +.gradle +.idea +.metadata +.project +.recommenders +.settings +.springBeans +.vscode +/code +MANIFEST.MF +_site/ +activemq-data +bin +build +!/**/src/**/bin +!/**/src/**/build +build.log +dependency-reduced-pom.xml +dump.rdb +interpolated*.xml +lib/ +manifest.yml +out +overridedb.* +target +.flattened-pom.xml +secrets.yml +.gradletasknamecache +.sts4-cache diff --git a/domain-services/ifix-department-entity-service/README.md b/domain-services/ifix-department-entity-service/README.md new file mode 100644 index 00000000..ad48c27a --- /dev/null +++ b/domain-services/ifix-department-entity-service/README.md @@ -0,0 +1 @@ +# iFIX-Department-Entity-Service \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/pom.xml b/domain-services/ifix-department-entity-service/pom.xml new file mode 100644 index 00000000..c7b4a231 --- /dev/null +++ b/domain-services/ifix-department-entity-service/pom.xml @@ -0,0 +1,100 @@ + + 4.0.0 + org.egov + ifix-department-entity-service + jar + ifix-department-entity-service + 1.0.0 + + 1.8 + ${java.version} + ${java.version} + + + org.springframework.boot + spring-boot-starter-parent + 2.2.6.RELEASE + + + src/main/java + + + org.springframework.boot + spring-boot-maven-plugin + + + + repackage + + + + + + + + + org.springframework.boot + spring-boot-starter-web + + + org.springframework.boot + spring-boot-starter-test + test + + + + io.swagger + swagger-core + 1.5.18 + + + + org.egov.services + ifix-tracer + 0.0.2-SNAPSHOT + + + org.egov.services + ifix-services-common + 0.0.1-SNAPSHOT + + + org.projectlombok + lombok + true + + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + + + javax.validation + validation-api + + + + org.springframework.boot + spring-boot-starter-data-mongodb + + + + + repo.digit.org + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/releases/ + + + repo.digit.org.snapshots + eGov ERP Releases Repository + https://nexus-repo.digit.org/nexus/content/repositories/snapshots/ + + + repo.digit.org.public + eGov Public Repository Group + https://nexus-repo.digit.org/nexus/content/groups/public/ + + + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/Main.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/Main.java new file mode 100644 index 00000000..fca48a16 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/Main.java @@ -0,0 +1,17 @@ +package org.egov; + + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.context.annotation.ComponentScan; + +@SpringBootApplication +@ComponentScan(basePackages = {"org.egov", "org.egov.web.controllers", "org.egov.config"}) +public class Main { + + + public static void main(String[] args) throws Exception { + SpringApplication.run(Main.class, args); + } + +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/IfixDepartmentEntityConfig.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/IfixDepartmentEntityConfig.java new file mode 100644 index 00000000..d3b8fcb3 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/IfixDepartmentEntityConfig.java @@ -0,0 +1,62 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + +@Component +@Data +@Import({TracerConfiguration.class}) +@NoArgsConstructor +@AllArgsConstructor +public class IfixDepartmentEntityConfig { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } + + @Value("${ifix.master.government.host}") + private String ifixMasterGovernmentHost; + + @Value("${ifix.master.government.context.path}") + private String ifixMasterGovernmentContextPath; + + @Value("${ifix.master.government.search.path}") + private String ifixMasterGovernmentSearchPath; + + @Value("${ifix.master.department.host}") + private String ifixMasterDepartmentHost; + + @Value("${ifix.master.department.context.path}") + private String ifixMasterDepartmentContextPath; + + @Value("${ifix.master.department.search.path}") + private String ifixMasterDepartmentSearchPath; + + @Value("${maximum.supported.department.hierarchy}") + private Integer maximumSupportedDepartmentHierarchy; + +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/MainConfiguration.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/MainConfiguration.java new file mode 100644 index 00000000..e4d1cb86 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/config/MainConfiguration.java @@ -0,0 +1,39 @@ +package org.egov.config; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.egov.tracer.config.TracerConfiguration; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Import; +import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter; + +import javax.annotation.PostConstruct; +import java.util.TimeZone; + + +@Import({TracerConfiguration.class}) +public class MainConfiguration { + + @Value("${app.timezone}") + private String timeZone; + + @PostConstruct + public void initialize() { + TimeZone.setDefault(TimeZone.getTimeZone(timeZone)); + } + + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES).setTimeZone(TimeZone.getTimeZone(timeZone)); + } + + @Bean + @Autowired + public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectMapper) { + MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter(); + converter.setObjectMapper(objectMapper); + return converter; + } +} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java new file mode 100644 index 00000000..91afbe0a --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java @@ -0,0 +1,48 @@ +package org.egov.repository; + +import org.apache.commons.lang3.StringUtils; +import org.egov.repository.queryBuilder.DepartmentEntityQueryBuilder; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.DepartmentEntitySearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; + +import java.util.Collections; +import java.util.List; + +@Repository +public class DepartmentEntityRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private DepartmentEntityQueryBuilder queryBuilder; + + /** + * @param departmentEntity + */ + public void save(DepartmentEntity departmentEntity) { + mongoTemplate.save(departmentEntity); + } + + public DepartmentEntity getParent(String childId) { + Criteria criteria = Criteria.where("children").all(Collections.singletonList(childId)); + Query query = Query.query(criteria); + List results = mongoTemplate.find(query, DepartmentEntity.class, "departmentEntity"); + if(!results.isEmpty()) + return results.get(0); + return null; + } + + public List searchEntity(DepartmentEntitySearchRequest departmentEntitySearchRequest) { + if (StringUtils.isNotBlank(departmentEntitySearchRequest.getCriteria().getTenantId())) { + Query searchQuery = queryBuilder.buildPlainSearchQuery(departmentEntitySearchRequest.getCriteria()); + return (mongoTemplate.find(searchQuery, DepartmentEntity.class)); + } + return Collections.emptyList(); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java new file mode 100644 index 00000000..68f8fe4f --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java @@ -0,0 +1,33 @@ +package org.egov.repository; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.repository.queryBuilder.DepartmentHierarchyLevelQueryBuilder; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Slf4j +public class DepartmentHierarchyLevelRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private DepartmentHierarchyLevelQueryBuilder queryBuilder; + + public void save(DepartmentHierarchyLevel departmentHierarchyLevel) { + mongoTemplate.save(departmentHierarchyLevel); + } + + public List searchDeptHierarchyLevel(DepartmentHierarchyLevelSearchCriteria searchCriteria) { + Query searchQuery = queryBuilder.buildSearchQuery(searchCriteria); + return (mongoTemplate.find(searchQuery, DepartmentHierarchyLevel.class)); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/ServiceRequestRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/ServiceRequestRepository.java new file mode 100644 index 00000000..9bfe652c --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/ServiceRequestRepository.java @@ -0,0 +1,48 @@ +package org.egov.repository; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import lombok.extern.slf4j.Slf4j; +import org.egov.tracer.model.ServiceCallException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import org.springframework.web.client.HttpClientErrorException; +import org.springframework.web.client.RestTemplate; + +import java.util.Map; + +@Component +@Slf4j +public class ServiceRequestRepository { + + private ObjectMapper mapper; + + private RestTemplate restTemplate; + + + @Autowired + public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) { + this.mapper = mapper; + this.restTemplate = restTemplate; + } + + /** + * @param uri + * @param request + * @return + */ + public Object fetchResult(String uri, Object request) { + mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false); + Object response = null; + try { + response = restTemplate.postForObject(uri, request, Map.class); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); + throw new ServiceCallException(e.getResponseBodyAsString()); + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); + } + + return response; + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java new file mode 100644 index 00000000..eab52b32 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java @@ -0,0 +1,35 @@ +package org.egov.repository.queryBuilder; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.web.models.DepartmentEntitySearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class DepartmentEntityQueryBuilder { + + public Query buildPlainSearchQuery(DepartmentEntitySearchCriteria searchCriteria) { + + Criteria criteria = Criteria.where("tenantId").is(searchCriteria.getTenantId()); + + if (StringUtils.isNotBlank(searchCriteria.getDepartmentId())) + criteria.and("departmentId").is(searchCriteria.getDepartmentId()); + + if (StringUtils.isNotBlank(searchCriteria.getCode())) + criteria.and("code").is(searchCriteria.getCode()); + + if (StringUtils.isNotBlank(searchCriteria.getName())) + criteria.and("name").is(searchCriteria.getName()); + + if (StringUtils.isNotBlank(searchCriteria.getHierarchyLevel())) + criteria.and("hierarchyLevel").is(searchCriteria.getHierarchyLevel()); + + if (searchCriteria.getIds() != null && !searchCriteria.getIds().isEmpty()) + criteria.and("id").in(searchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java new file mode 100644 index 00000000..2848647a --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java @@ -0,0 +1,33 @@ +package org.egov.repository.queryBuilder; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class DepartmentHierarchyLevelQueryBuilder { + + public Query buildSearchQuery(DepartmentHierarchyLevelSearchCriteria searchCriteria) { + + Criteria criteria = Criteria.where("tenantId").is(searchCriteria.getTenantId()); + + if (StringUtils.isNotBlank(searchCriteria.getDepartmentId())) + criteria.and("departmentId").is(searchCriteria.getDepartmentId()); + + if (StringUtils.isNotBlank(searchCriteria.getLabel())) + criteria.and("label").is(searchCriteria.getLabel()); + + if (searchCriteria.getLevel() != null) + criteria.and("level").is(searchCriteria.getLevel()); + + if (searchCriteria.getIds() != null && !searchCriteria.getIds().isEmpty()) + criteria.and("id").in(searchCriteria.getIds()); + + return new Query(criteria); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java new file mode 100644 index 00000000..46dca0f8 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java @@ -0,0 +1,36 @@ +package org.egov.service; + +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.DepartmentEntityUtil; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.DepartmentEntityRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.UUID; + +@Component +public class DepartmentEntityEnrichmentService { + @Autowired + DepartmentEntityUtil enrichAuditDetails; + + /** + * @param departmentEntityRequest + */ + public void enrichDepartmentEntityData(DepartmentEntityRequest departmentEntityRequest) { + DepartmentEntity departmentEntity = departmentEntityRequest.getDepartmentEntity(); + RequestHeader requestHeader = departmentEntityRequest.getRequestHeader(); + + AuditDetails auditDetails = null; + + if(departmentEntity.getAuditDetails() == null){ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentEntity.getAuditDetails(), true); + }else{ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentEntity.getAuditDetails(), false); + } + + departmentEntity.setId(UUID.randomUUID().toString()); + departmentEntity.setAuditDetails(auditDetails); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java new file mode 100644 index 00000000..c11f43e2 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java @@ -0,0 +1,81 @@ +package org.egov.service; + +import org.egov.config.IfixDepartmentEntityConfig; +import org.egov.repository.DepartmentEntityRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.DepartmentEntityAncestryUtil; +import org.egov.validator.DepartmentEntityValidator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.ArrayList; +import java.util.List; + +@Service +public class DepartmentEntityService { + + @Autowired + DepartmentEntityValidator departmentEntityValidator; + + @Autowired + DepartmentEntityEnrichmentService entityEnrichmentService; + + @Autowired + DepartmentEntityRepository entityRepository; + + @Autowired + private IfixDepartmentEntityConfig ifixDepartmentEntityConfig; + + @Autowired + private DepartmentEntityAncestryUtil departmentEntityAncestryUtil; + + /** + * @param departmentEntityRequest + * @return + */ + public DepartmentEntityRequest createDepartmentEntity(DepartmentEntityRequest departmentEntityRequest) { + departmentEntityValidator.validateDepartmentEntityRequest(departmentEntityRequest); + entityEnrichmentService.enrichDepartmentEntityData(departmentEntityRequest); + entityRepository.save(departmentEntityRequest.getDepartmentEntity()); + + return departmentEntityRequest; + } + + public List findAllByCriteria(DepartmentEntitySearchRequest departmentEntitySearchRequest) { + List departmentEntityList = entityRepository.searchEntity(departmentEntitySearchRequest); + if(departmentEntitySearchRequest.getCriteria().isGetAncestry()) { + List departmentEntityAncestryList = new ArrayList<>(); + for(DepartmentEntity departmentEntity : departmentEntityList) { + departmentEntityAncestryList.add(createAncestryFor(departmentEntity)); + } + return departmentEntityAncestryList; + } + return departmentEntityList; + } + + public DepartmentEntityAncestry createAncestryFor(DepartmentEntity departmentEntity) { + int hierarchyCount = ifixDepartmentEntityConfig.getMaximumSupportedDepartmentHierarchy(); + DepartmentEntityAncestry ancestry = + departmentEntityAncestryUtil.createDepartmentEntityAncestryFromDepartmentEntity(departmentEntity); + while (hierarchyCount >= 0) { + DepartmentEntity parentEntity = entityRepository.getParent(ancestry.getId()); + if(parentEntity == null) + break; + + DepartmentEntityAncestry parentAncestry = + departmentEntityAncestryUtil.createDepartmentEntityAncestryFromDepartmentEntity(parentEntity); + parentAncestry.getChildren().add(ancestry); + + ancestry = parentAncestry; + hierarchyCount--; + } + + if(hierarchyCount < 0) + throw new CustomException("MAXIMUM_SUPPORTED_HIERARCHY_EXCEEDED", "Loop to find ancestors " + + "exceeded the maximum supported hierarchy. The data might be corrupted."); + + return ancestry; + } + +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java new file mode 100644 index 00000000..d6e42f5e --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java @@ -0,0 +1,70 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.DepartmentHierarchyLevelRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.DepartmentEntityUtil; +import org.egov.web.models.DepartmentEntitySearchCriteria; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelRequest; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; +import java.util.UUID; + +@Service +@Slf4j +public class DepartmentHierarchyLevelEnrichmentService { + + @Autowired + private DepartmentEntityUtil departmentEntityUtil; + + @Autowired + private DepartmentHierarchyLevelRepository levelRepository; + + /** + * Enrich the Department hierarchy level request + * @param request + */ + public void enrichHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest request) { + RequestHeader requestHeader = request.getRequestHeader(); + DepartmentHierarchyLevel departmentHierarchyLevel = request.getDepartmentHierarchyLevel(); + + AuditDetails auditDetails = null; + if (departmentHierarchyLevel.getAuditDetails() == null) { + auditDetails = departmentEntityUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentHierarchyLevel.getAuditDetails(), true); + } else { + auditDetails = departmentEntityUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentHierarchyLevel.getAuditDetails(), false); + } + + enrichDepartmentLevel(departmentHierarchyLevel); + + departmentHierarchyLevel.setId(UUID.randomUUID().toString()); + departmentHierarchyLevel.setAuditDetails(auditDetails); + } + + private void enrichDepartmentLevel(DepartmentHierarchyLevel departmentHierarchyLevel) { + if (StringUtils.isNotBlank(departmentHierarchyLevel.getParent()) && StringUtils.isNotBlank(departmentHierarchyLevel.getTenantId())) { + DepartmentHierarchyLevelSearchCriteria searchCriteria = new DepartmentHierarchyLevelSearchCriteria(); + searchCriteria.setIds(Collections.singletonList(departmentHierarchyLevel.getParent())); + searchCriteria.setTenantId(departmentHierarchyLevel.getTenantId()); + + List dbDepartmentHierarchyLevels = levelRepository.searchDeptHierarchyLevel(searchCriteria); + //Rare scenario - may be in case of corrupted data + if (dbDepartmentHierarchyLevels == null || dbDepartmentHierarchyLevels.isEmpty()) { + throw new CustomException("INVALID_PARENT_ID", "Given parent doesn't exist in the system"); + } + //set the hierarchy level + if (dbDepartmentHierarchyLevels.get(0).getLevel() != null) { + departmentHierarchyLevel.setLevel(dbDepartmentHierarchyLevels.get(0).getLevel() + 1); + } + } + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelService.java new file mode 100644 index 00000000..139be371 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelService.java @@ -0,0 +1,70 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.repository.DepartmentHierarchyLevelRepository; +import org.egov.validator.DepartmentHierarchyLevelValidator; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelRequest; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.egov.web.models.DepartmentHierarchyLevelSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.Collections; +import java.util.List; + +@Service +@Slf4j +public class DepartmentHierarchyLevelService { + + @Autowired + private DepartmentHierarchyLevelValidator validator; + + @Autowired + private DepartmentHierarchyLevelEnrichmentService enricher; + + @Autowired + private DepartmentHierarchyLevelRepository hierarchyLevelRepository; + + /** + * validate the department hierarchy level request , enrich and save the details in + * db and return the enriched request + * + * @param request + * @return + */ + public DepartmentHierarchyLevelRequest createDepartmentEntityHierarchyLevel(DepartmentHierarchyLevelRequest request) { + validator.validateHierarchyLevelCreatePost(request); + enricher.enrichHierarchyLevelCreatePost(request); + hierarchyLevelRepository.save(request.getDepartmentHierarchyLevel()); + return request; + } + + /** + * Validate the search request, enrich, search w.r.t parameters And return the result. + * + * @param searchRequest + * @return + */ + public List searchDepartmentEntityHierarchyLevel(DepartmentHierarchyLevelSearchRequest searchRequest) { + validator.validateHierarchyLevelSearchPost(searchRequest); + //enricher.enrichHierarchyLevelSearchPost(searchRequest); + DepartmentHierarchyLevelSearchCriteria searchCriteria = searchRequest.getCriteria(); + + if ((searchCriteria.getIds() == null || searchCriteria.getIds().isEmpty()) && StringUtils.isBlank(searchCriteria.getDepartmentId()) + && StringUtils.isBlank(searchCriteria.getLabel()) && StringUtils.isBlank(searchCriteria.getTenantId()) + && searchCriteria.getLevel() == null) { + + return Collections.emptyList(); + } + + List departmentHierarchyLevels = hierarchyLevelRepository.searchDeptHierarchyLevel(searchCriteria); + + if (departmentHierarchyLevels == null || departmentHierarchyLevels.isEmpty()) + return Collections.emptyList(); + + return departmentHierarchyLevels; + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java new file mode 100644 index 00000000..ae77e799 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java @@ -0,0 +1,30 @@ +package org.egov.util; + +import lombok.extern.slf4j.Slf4j; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.DepartmentEntityAncestry; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; + +@Component +@Slf4j +public class DepartmentEntityAncestryUtil { + + public DepartmentEntityAncestry createDepartmentEntityAncestryFromDepartmentEntity(DepartmentEntity departmentEntity) { + DepartmentEntityAncestry departmentEntityAncestry = DepartmentEntityAncestry.builder().build(); + departmentEntityAncestry.setId(departmentEntity.getId()); + departmentEntityAncestry.setTenantId(departmentEntity.getTenantId()); + departmentEntityAncestry.setDepartmentId(departmentEntity.getDepartmentId()); + departmentEntityAncestry.setCode(departmentEntity.getCode()); + departmentEntityAncestry.setName(departmentEntity.getName()); + departmentEntityAncestry.setHierarchyLevel(departmentEntity.getHierarchyLevel()); + departmentEntityAncestry.setAuditDetails(departmentEntity.getAuditDetails()); + + departmentEntityAncestry.setChildren(new ArrayList<>()); + + return departmentEntityAncestry; + } + +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java new file mode 100644 index 00000000..015e1a78 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java @@ -0,0 +1,32 @@ +package org.egov.util; + +public class DepartmentEntityConstant { + + private DepartmentEntityConstant(){} + + public static final String USER_INFO = "USER_INFO"; + public static final String TENANT_ID = "TENANT_ID"; + public static final String DEPARTMENT_ENTITY_CODE = "DEPARTMENT_ENTITY_CODE"; + public static final String DEPARTMENT_ENTITY_NAME = "DEPARTMENT_ENTITY_NAME"; + public static final String DEPARTMENT_HIERARCHY_ID = "DEPARTMENT_HIERARCHY_ID"; + public static final String REQUEST_PAYLOAD_MISSING = "REQUEST_PAYLOAD"; + public static final String ERROR_REQUEST_HEADER = "REQUEST_HEADER"; + public static final String INVALID_REQUEST = "INVALID_REQUEST"; + public static final String DEPARTMENT_ID = "DEPARTMENT_ID"; + public static final String DEPARTMENT_LABEL = "DEPARTMENT_LABEL"; + public static final String INVALID_TENANT_ID = "INVALID_TENANT_ID"; + public static final String INVALID_DEPARTMENT_ID = "INVALID_DEPARTMENT_ID"; + public static final String ERROR_SEARCH_CRITERIA = "SEARCH_CRITERIA"; + + //Search key parameters + public static final String IDS = "Ids"; + public static final String REQUEST_HEADER = "requestHeader"; + public static final String CRITERIA = "criteria"; + public static final String CRITERIA_TENANT_ID = "tenantId"; + + //json path + public static final String GOVERNMENT_LIST = "$.government.*"; + public static final String DEPARTMENT_JSON_PATH = "$.department.*"; + + public static final String JSONPATH_ERROR = "JSONPATH_ERROR"; +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java new file mode 100644 index 00000000..1f771f16 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java @@ -0,0 +1,28 @@ +package org.egov.util; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.springframework.stereotype.Component; + + +@Component +@Slf4j +public class DepartmentEntityUtil { + + + /** + * Method to return auditDetails of fiscal event request + * + * @param by + * @param isCreate + * @return AuditDetails + */ + public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { + Long time = System.currentTimeMillis(); + if(isCreate) + return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); + else + return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) + .createdTime(auditDetails.getCreatedTime()).lastModifiedTime(time).build(); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java new file mode 100644 index 00000000..63e180de --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java @@ -0,0 +1,67 @@ +package org.egov.util; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.IfixDepartmentEntityConfig; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class DepartmentUtil { + + @Autowired + private IfixDepartmentEntityConfig entityConfig; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + + /** + * + * @param tenantId + * @param departmentId + * @param requestHeader + * @return + */ + public List getDepartmentFromDepartmentService(String tenantId,String departmentId, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId) && StringUtils.isNotBlank(departmentId)) { + + Map departmentValueMap = new HashMap<>(); + departmentValueMap.put(DepartmentEntityConstant.IDS, Collections.singletonList(departmentId.trim())); + departmentValueMap.put(DepartmentEntityConstant.CRITERIA_TENANT_ID, tenantId.trim()); + + Map departmentMap = new HashMap<>(); + departmentMap.put(DepartmentEntityConstant.REQUEST_HEADER, requestHeader); + departmentMap.put(DepartmentEntityConstant.CRITERIA, departmentValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchDepartmentUrl(), departmentMap); + + try { + List departmentList = JsonPath.read(response, DepartmentEntityConstant.DEPARTMENT_JSON_PATH); + return departmentList; + } catch (Exception e) { + throw new CustomException(DepartmentEntityConstant.JSONPATH_ERROR, "Failed to parse department response for department Id"); + } + } + return Collections.emptyList(); + } + + private String createSearchDepartmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(entityConfig.getIfixMasterDepartmentHost()) + .append(entityConfig.getIfixMasterDepartmentContextPath()) + .append(entityConfig.getIfixMasterDepartmentSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java new file mode 100644 index 00000000..add23593 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java @@ -0,0 +1,67 @@ +package org.egov.util; + +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.IfixDepartmentEntityConfig; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class GovernmentUtil { + + @Autowired + private IfixDepartmentEntityConfig configuration; + + @Autowired + private ServiceRequestRepository serviceRequestRepository; + + /** + * + * @param tenantId + * @param requestHeader + * @return + */ + public List getGovernmentFromGovernmentService(String tenantId, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId)) { + Map tenantValueMap = new HashMap<>(); + tenantValueMap.put(DepartmentEntityConstant.IDS, + Collections.singletonList(tenantId.trim())); + + Map tenantMap = new HashMap<>(); + tenantMap.put(DepartmentEntityConstant.REQUEST_HEADER, requestHeader); + tenantMap.put(DepartmentEntityConstant.CRITERIA, tenantValueMap); + + Object response = serviceRequestRepository.fetchResult(createSearchGovernmentUrl(), tenantMap); + try { + List governments = JsonPath.read(response, DepartmentEntityConstant.GOVERNMENT_LIST); + return governments; + } catch (Exception e) { + throw new CustomException(DepartmentEntityConstant.JSONPATH_ERROR, "Failed to parse government response for tenantId"); + } + } + return Collections.emptyList(); + } + + + /** + * @return + */ + private String createSearchGovernmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getIfixMasterGovernmentHost()) + .append(configuration.getIfixMasterGovernmentContextPath()) + .append(configuration.getIfixMasterGovernmentSearchPath()); + return uriBuilder.toString(); + } + +} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java new file mode 100644 index 00000000..c802136b --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -0,0 +1,26 @@ +package org.egov.util; + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.request.RequestHeader; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class ResponseHeaderCreator { + + public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader requestInfo, final Boolean success) { + + final String correlationId = requestInfo != null ? requestInfo.getCorrelationId() : ""; + final String ver = requestInfo != null ? requestInfo.getVersion() : ""; + Long ts = null; + if (requestInfo != null) + ts = requestInfo.getTs(); + final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; + final String responseStatus = success ? "successful" : "failed"; + + return ResponseHeader.builder().version(ver).ts(ts).msgId(msgId).correlationId(correlationId).signature(sign) + .status(responseStatus).build(); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java new file mode 100644 index 00000000..635b24a8 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -0,0 +1,92 @@ +package org.egov.validator; + +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.util.DepartmentEntityConstant; +import org.egov.util.GovernmentUtil; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.DepartmentEntityRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +public class DepartmentEntityValidator { + + @Autowired + private GovernmentUtil governmentUtil; + + /** + * TODO: validation of HierarchyLevel and department id check. + * Both combination should be checked in Department Hierarchy Level meta data. + * + * @param departmentEntityRequest + * @return + */ + public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEntityRequest) { + Map errorMap = new HashMap<>(); + + if (departmentEntityRequest != null && departmentEntityRequest.getRequestHeader() != null + && departmentEntityRequest.getDepartmentEntity() != null) { + + RequestHeader requestHeader = departmentEntityRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + errorMap.put(DepartmentEntityConstant.USER_INFO, "User information is missing"); + } + + DepartmentEntity departmentEntity = departmentEntityRequest.getDepartmentEntity(); + + if (StringUtils.isEmpty(departmentEntity.getTenantId())) { + errorMap.put(DepartmentEntityConstant.TENANT_ID, "Tenant id is missing in request data"); + }else if (departmentEntity.getTenantId().length() < 2 || departmentEntity.getTenantId().length() > 64) { + errorMap.put(DepartmentEntityConstant.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + }else { + List governments = governmentUtil.getGovernmentFromGovernmentService(departmentEntity.getTenantId(),requestHeader); + if (governments.isEmpty()) + errorMap.put(DepartmentEntityConstant.INVALID_TENANT_ID, "Tenant id : " + departmentEntity.getTenantId() + + " doesn't exist in the system"); + } + + if (StringUtils.isEmpty(departmentEntity.getCode())) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_CODE, "Department entity code" + + " is missing in request data"); + }else if (departmentEntity.getCode().length() < 1 || departmentEntity.getCode().length() > 256) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_CODE, "Department entity code " + + "length is invalid. Length range [2-256]"); + } + + if (StringUtils.isEmpty(departmentEntity.getName())) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_NAME, "Department entity name" + + " is missing in request data"); + }else if (departmentEntity.getName().length() < 1 || departmentEntity.getName().length() > 256) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_NAME, "Department entity name " + + "length is invalid. Length range [2-256]"); + } + + if (departmentEntity.getHierarchyLevel() == null) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id" + + " is missing in request data"); + }else if (departmentEntity.getHierarchyLevel() < 1 || departmentEntity.getHierarchyLevel() > 256) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id " + + "length is invalid. Length range [2-256]"); + } + + if (departmentEntity.getChildren() == null) { + errorMap.put(DepartmentEntityConstant.USER_INFO, "Department children information is missing"); + } + + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + + }else { + throw new CustomException(DepartmentEntityConstant.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); + } + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java new file mode 100644 index 00000000..84458860 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java @@ -0,0 +1,107 @@ +package org.egov.validator; + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.tracer.model.CustomException; +import org.egov.util.DepartmentEntityConstant; +import org.egov.util.DepartmentUtil; +import org.egov.util.GovernmentUtil; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelRequest; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.egov.web.models.DepartmentHierarchyLevelSearchRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class DepartmentHierarchyLevelValidator { + + @Autowired + private GovernmentUtil governmentUtil; + + @Autowired + private DepartmentUtil departmentUtil; + + public void validateHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest request) { + DepartmentHierarchyLevel departmentHierarchyLevel = request.getDepartmentHierarchyLevel(); + RequestHeader requestHeader = request.getRequestHeader(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException(DepartmentEntityConstant.ERROR_REQUEST_HEADER, "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put(DepartmentEntityConstant.USER_INFO, "User info is missing"); + } + + if (departmentHierarchyLevel == null) { + throw new CustomException(DepartmentEntityConstant.INVALID_REQUEST, "Department hierarchy request is invalid"); + } + + if (StringUtils.isBlank(departmentHierarchyLevel.getTenantId())) { + errorMap.put(DepartmentEntityConstant.TENANT_ID, "Government Id (Tenant id) is missing"); + } + if (StringUtils.isBlank(departmentHierarchyLevel.getDepartmentId())) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_ID, "Department id is missing"); + } + if (StringUtils.isBlank(departmentHierarchyLevel.getLabel())) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_LABEL, "Department label is missing"); + } + + if (StringUtils.isNotBlank(departmentHierarchyLevel.getTenantId())) { + List governments = governmentUtil.getGovernmentFromGovernmentService(departmentHierarchyLevel.getTenantId(),requestHeader); + if (governments.isEmpty()) + errorMap.put(DepartmentEntityConstant.INVALID_TENANT_ID, "Tenant id : " + departmentHierarchyLevel.getTenantId() + + " doesn't exist in the system"); + } + + if (StringUtils.isNotBlank(departmentHierarchyLevel.getDepartmentId()) && StringUtils.isNotBlank(departmentHierarchyLevel.getTenantId())) { + List departments = departmentUtil.getDepartmentFromDepartmentService(departmentHierarchyLevel.getTenantId(), + departmentHierarchyLevel.getDepartmentId(), requestHeader); + if (departments.isEmpty()) + errorMap.put(DepartmentEntityConstant.INVALID_DEPARTMENT_ID, "Department id : " + departmentHierarchyLevel.getDepartmentId() + + " doesn't exist in the system"); + } + + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } + + public void validateHierarchyLevelSearchPost(DepartmentHierarchyLevelSearchRequest searchRequest) { + DepartmentHierarchyLevelSearchCriteria searchCriteria = searchRequest.getCriteria(); + RequestHeader requestHeader = searchRequest.getRequestHeader(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException(DepartmentEntityConstant.ERROR_REQUEST_HEADER, "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put(DepartmentEntityConstant.USER_INFO, "User info is missing"); + } + if (searchCriteria == null) { + throw new CustomException(DepartmentEntityConstant.ERROR_SEARCH_CRITERIA, "Search criteria is missing"); + } + if (StringUtils.isBlank(searchCriteria.getTenantId())) { + errorMap.put(DepartmentEntityConstant.TENANT_ID, "Government Id (Tenant id) is missing"); + } + + if (StringUtils.isNotBlank(searchCriteria.getTenantId())) { + List governments = governmentUtil.getGovernmentFromGovernmentService(searchCriteria.getTenantId(), requestHeader); + if (governments.isEmpty()) + errorMap.put(DepartmentEntityConstant.INVALID_TENANT_ID, "Tenant id : " + searchCriteria.getTenantId() + + " doesn't exist in the system"); + } + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java new file mode 100644 index 00000000..6df8cb9c --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java @@ -0,0 +1,86 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.DepartmentEntityService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.io.IOException; +import java.util.Collections; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Controller +@RequestMapping("/departmentEntity/v1") +public class DepartmentEntityApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + DepartmentEntityService departmentEntityService; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + public DepartmentEntityApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + /** + * @param body + * @return + */ + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity departmentEntityV1CreatePost( + @ApiParam(value = "Details for the new Department Entity RequestHeader (meta data of the API).", + required = true) + @Valid @RequestBody DepartmentEntityRequest body) { + + DepartmentEntityRequest departmentEntityRequest = departmentEntityService.createDepartmentEntity(body); + + ResponseHeader responseHeader = responseHeaderCreator + .createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + + DepartmentEntityResponse departmentEntityResponse = DepartmentEntityResponse.builder() + .responseHeader(responseHeader) + .departmentEntity(Collections.singletonList(departmentEntityRequest.getDepartmentEntity())).build(); + + return new ResponseEntity(departmentEntityResponse, HttpStatus.OK); + } + + /** + * @param body + * @return + */ + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity departmentEntityV1SearchPost( + @ApiParam(value = "RequestHeader meta data.", required = true) + @Valid @RequestBody DepartmentEntitySearchRequest body) { + List departmentEntityList = departmentEntityService.findAllByCriteria(body); + ResponseHeader responseHeader = responseHeaderCreator + .createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + DepartmentEntityResponse departmentEntityResponse = DepartmentEntityResponse.builder() + .responseHeader(responseHeader) + .departmentEntity(departmentEntityList).build(); + + return new ResponseEntity(departmentEntityResponse, HttpStatus.OK); + } + +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java new file mode 100644 index 00000000..28e4f33c --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java @@ -0,0 +1,63 @@ +package org.egov.web.controllers; + + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.swagger.annotations.ApiParam; +import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.DepartmentHierarchyLevelService; +import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestMethod; + +import javax.servlet.http.HttpServletRequest; +import javax.validation.Valid; +import java.util.Collections; +import java.util.List; + +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Controller +@RequestMapping("/departmentEntity/hierarchyLevel/v1") +public class DepartmentHierarchyLevelApiController { + + private final ObjectMapper objectMapper; + + private final HttpServletRequest request; + + @Autowired + private ResponseHeaderCreator responseHeaderCreator; + + @Autowired + private DepartmentHierarchyLevelService hierarchyLevelService; + + + @Autowired + public DepartmentHierarchyLevelApiController(ObjectMapper objectMapper, HttpServletRequest request) { + this.objectMapper = objectMapper; + this.request = request; + } + + @RequestMapping(value = "/_create", method = RequestMethod.POST) + public ResponseEntity departmentEntityHierarchyLevelV1CreatePost(@ApiParam(value = "Details for the new DepartmentHierarchyLevel + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody DepartmentHierarchyLevelRequest body) { + DepartmentHierarchyLevelRequest departmentHierarchyLevelRequest = hierarchyLevelService.createDepartmentEntityHierarchyLevel(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + DepartmentHierarchyLevelResponse departmentHierarchyLevelResponse = DepartmentHierarchyLevelResponse.builder().responseHeader(responseHeader) + .departmentHierarchyLevel(Collections.singletonList(departmentHierarchyLevelRequest.getDepartmentHierarchyLevel())).build(); + return new ResponseEntity(departmentHierarchyLevelResponse, HttpStatus.OK); + } + + @RequestMapping(value = "/_search", method = RequestMethod.POST) + public ResponseEntity departmentEntityHierarchyLevelV1SearchPost(@ApiParam(value = "RequestHeader meta data.", required = true) @Valid @RequestBody DepartmentHierarchyLevelSearchRequest body) { + List departmentHierarchyLevels = hierarchyLevelService.searchDepartmentEntityHierarchyLevel(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + DepartmentHierarchyLevelResponse departmentHierarchyLevelResponse = DepartmentHierarchyLevelResponse.builder().responseHeader(responseHeader) + .departmentHierarchyLevel(departmentHierarchyLevels).build(); + return new ResponseEntity(departmentHierarchyLevelResponse, HttpStatus.OK); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java new file mode 100644 index 00000000..605936e0 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java @@ -0,0 +1,37 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * This object captures the information for department entity + */ +@ApiModel(description = "This object captures the information for department entity") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntity extends DepartmentEntityAbstract { + @JsonProperty("children") + @Valid + private List children = new ArrayList<>(); + + public DepartmentEntity addChildrenItem(String childrenItem) { + this.children.add(childrenItem); + return this; + } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java new file mode 100644 index 00000000..df385482 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java @@ -0,0 +1,47 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * This object captures the information for department entity + */ +@ApiModel(description = "This object captures the information for department entity") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public abstract class DepartmentEntityAbstract { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("hierarchyLevel") + private Integer hierarchyLevel = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java new file mode 100644 index 00000000..3f8a2c1c --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java @@ -0,0 +1,37 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * This object captures the information for department entity + */ +@ApiModel(description = "This object captures the information for department entity") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntityAncestry extends DepartmentEntityAbstract { + + @JsonProperty("children") + @Valid + private List children = new ArrayList<>(); + + public DepartmentEntityAncestry addChildrenItem(DepartmentEntityAncestry childrenItem) { + this.children.add(childrenItem); + return this; + } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityRequest.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityRequest.java new file mode 100644 index 00000000..3daaaed1 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department Entity request along with request metadata + */ +@ApiModel(description = "Department Entity request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntityRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("departmentEntity") + private DepartmentEntity departmentEntity = null; + + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java new file mode 100644 index 00000000..2ce350fc --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java @@ -0,0 +1,42 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched Department Entity information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched Department Entity information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntityResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("departmentEntity") + @Valid + private List departmentEntity = null; + +// public DepartmentEntityResponse addDepartmentEntityItem(Object departmentEntityItem) { +// if (this.departmentEntity == null) { +// this.departmentEntity = new ArrayList<>(); +// } +// this.departmentEntity.add(departmentEntityItem); +// return this; +// } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchCriteria.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchCriteria.java new file mode 100644 index 00000000..78b9c154 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchCriteria.java @@ -0,0 +1,57 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of Department Entity + */ +@ApiModel(description = "The object contains all the search criteria of Department Entity") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntitySearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("code") + private String code = null; + + @JsonProperty("name") + private String name = null; + + @JsonProperty("hierarchyLevel") + private String hierarchyLevel = null; + + @JsonProperty("getAncestry") + private boolean getAncestry = false; + + + public DepartmentEntitySearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchRequest.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchRequest.java new file mode 100644 index 00000000..1e617bbd --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntitySearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department Entity search request along with request metadata + */ +@ApiModel(description = "Department Entity search request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentEntitySearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private DepartmentEntitySearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java new file mode 100644 index 00000000..422fd2e7 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java @@ -0,0 +1,47 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.AuditDetails; +import org.springframework.validation.annotation.Validated; + +import java.math.BigDecimal; + +/** + * This object captures the information for level of the department hierarchy and it's alias + */ +@ApiModel(description = "This object captures the information for level of the department hierarchy and it's alias") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentHierarchyLevel { + @JsonProperty("id") + private String id = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("label") + private String label = null; + + @JsonProperty("parent") + private String parent = null; + + @JsonProperty("level") + private Integer level = null; + + @JsonProperty("auditDetails") + private AuditDetails auditDetails = null; + + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelRequest.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelRequest.java new file mode 100644 index 00000000..68ef1815 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department Hierarchy Level request along with request metadata + */ +@ApiModel(description = "Department Hierarchy Level request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentHierarchyLevelRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("departmentHierarchyLevel") + private DepartmentHierarchyLevel departmentHierarchyLevel = null; + + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelResponse.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelResponse.java new file mode 100644 index 00000000..b32c5c13 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelResponse.java @@ -0,0 +1,43 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.response.ResponseHeader; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.util.ArrayList; +import java.util.List; + +/** + * Contains the ResponseHeader and the enriched Department Hierarchy Level information + */ +@ApiModel(description = "Contains the ResponseHeader and the enriched Department Hierarchy Level information") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentHierarchyLevelResponse { + @JsonProperty("responseHeader") + private ResponseHeader responseHeader = null; + + @JsonProperty("departmentHierarchyLevel") + @Valid + private List departmentHierarchyLevel = null; + + + public DepartmentHierarchyLevelResponse addDepartmentHierarchyLevelItem(DepartmentHierarchyLevel departmentHierarchyLevelItem) { + if (this.departmentHierarchyLevel == null) { + this.departmentHierarchyLevel = new ArrayList<>(); + } + this.departmentHierarchyLevel.add(departmentHierarchyLevelItem); + return this; + } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java new file mode 100644 index 00000000..e91f3c02 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java @@ -0,0 +1,52 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.springframework.validation.annotation.Validated; + +import javax.validation.Valid; +import java.math.BigDecimal; +import java.util.ArrayList; +import java.util.List; + +/** + * The object contains all the search criteria of Department Hierarchy Level + */ +@ApiModel(description = "The object contains all the search criteria of Department Hierarchy Level") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentHierarchyLevelSearchCriteria { + @JsonProperty("Ids") + @Valid + private List ids = null; + + @JsonProperty("tenantId") + private String tenantId = null; + + @JsonProperty("departmentId") + private String departmentId = null; + + @JsonProperty("label") + private String label = null; + + @JsonProperty("level") + private Integer level = null; + + + public DepartmentHierarchyLevelSearchCriteria addIdsItem(String idsItem) { + if (this.ids == null) { + this.ids = new ArrayList<>(); + } + this.ids.add(idsItem); + return this; + } + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchRequest.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchRequest.java new file mode 100644 index 00000000..27defd25 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchRequest.java @@ -0,0 +1,30 @@ +package org.egov.web.models; + +import com.fasterxml.jackson.annotation.JsonProperty; +import io.swagger.annotations.ApiModel; +import lombok.*; +import org.egov.common.contract.request.RequestHeader; +import org.springframework.validation.annotation.Validated; + +/** + * Department Hierarchy Level search request along with request metadata + */ +@ApiModel(description = "Department Hierarchy Level search request along with request metadata") +@Validated +@javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-23T11:51:49.710+05:30") + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class DepartmentHierarchyLevelSearchRequest { + @JsonProperty("requestHeader") + private RequestHeader requestHeader = null; + + @JsonProperty("criteria") + private DepartmentHierarchyLevelSearchCriteria criteria = null; + + +} + diff --git a/domain-services/ifix-department-entity-service/src/main/resources/application.properties b/domain-services/ifix-department-entity-service/src/main/resources/application.properties new file mode 100644 index 00000000..6aa60aed --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/resources/application.properties @@ -0,0 +1,19 @@ +server.servlet.contextPath=/ifix-department-entity +server.port=8032 +app.timezone=UTC +org.egov.detailed.tracing.enabled=false + +maximum.supported.department.hierarchy=10 + +#mongoDB +spring.data.mongodb.uri=mongodb://localhost:27017/?retryWrites=false +spring.data.mongodb.database=ifix_dev_db + +## Uri Configurations ## +ifix.master.government.host=http://localhost:8030 +ifix.master.government.context.path=/ifix-master-data +ifix.master.government.search.path=/government/v1/_search + +ifix.master.department.host=http://localhost:8030 +ifix.master.department.context.path=/ifix-master-data +ifix.master.department.search.path=/department/v1/_search diff --git a/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index b/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index new file mode 100644 index 00000000..b40e3fc8 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/resources/db/migration/V20210824122400__create_index @@ -0,0 +1,10 @@ +db.departmentHierarchyLevel.createIndexes( + [{"departmentId":1},{"label":1},{"tenantId":1},{"level":1}] + ); +db.departmentHierarchyLevel.getIndexes(); + +db.departmentEntity.createIndexes( + [{"departmentId":1},{"code":1},{"tenantId":1},{"level":1},{"name":1},{"children":1}] + ); +db.departmentEntity.getIndexes(); + diff --git a/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192300__department_hierarchy_seed_data b/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192300__department_hierarchy_seed_data new file mode 100644 index 00000000..4c8fad86 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192300__department_hierarchy_seed_data @@ -0,0 +1,107 @@ +db.departmentHierarchyLevel.insertMany([ + { + "_id": "6c078c52-4ba0-4678-8e0d-288858d1b72b", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Department", + "level": 0, + "parent": null, + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "962b9e5a-1918-4434-b835-e4a83a97ac26", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Zone", + "level": 1, + "parent": "6c078c52-4ba0-4678-8e0d-288858d1b72b", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "346a4761-751f-44f0-8f62-b3a947930666", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Circle", + "level": 2, + "parent": "962b9e5a-1918-4434-b835-e4a83a97ac26", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "9785ce0e-9d8d-4767-9321-f84ac89d4c5c", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Division", + "level": 3, + "parent": "346a4761-751f-44f0-8f62-b3a947930666", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "11393730-c9c1-426c-b1a8-654daf687b5c", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Sub-Division", + "level": 4, + "parent": "9785ce0e-9d8d-4767-9321-f84ac89d4c5c", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "e17b42e6-d0dd-40e5-9f59-280fee9460cb", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "Section", + "level": 5, + "parent": "11393730-c9c1-426c-b1a8-654daf687b5c", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + }, + { + "_id": "c8bce244-92f2-44d3-94ab-018605601aa2", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "label": "GP", + "level": 6, + "parent": "e17b42e6-d0dd-40e5-9f59-280fee9460cb", + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentHierarchyLevel" + } +]); \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192400__department_entity_seed_data b/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192400__department_entity_seed_data new file mode 100644 index 00000000..0498dbbb --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/resources/db/seed/V20210824192400__department_entity_seed_data @@ -0,0 +1,146 @@ +db.departmentEntity.insertMany([ + { + "_id": "07fea07c-9ca9-4474-b6bc-c3a9456b181e", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "DWSS", + "name": "Department of Water Supply and Sanitation", + "hierarchyLevel": 0, + "children": ["5ac4d271-1a00-47b9-94e6-f44fe17ae1b6"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "5ac4d271-1a00-47b9-94e6-f44fe17ae1b6", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "Z02", + "name": "South", + "hierarchyLevel": 1, + "children": ["525f7b94-1755-426e-982f-430904554dd3"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "525f7b94-1755-426e-982f-430904554dd3", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "C05", + "name": "Chandigarh", + "hierarchyLevel": 2, + "children": ["901f76a8-1911-4960-b389-57b62bd4dcdb"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "901f76a8-1911-4960-b389-57b62bd4dcdb", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "DIV23", + "name": "Sri Anandpur Sahib", + "hierarchyLevel": 3, + "children": ["69c418a6-1bbf-4ef9-9bd2-bd26243d7c53"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "69c418a6-1bbf-4ef9-9bd2-bd26243d7c53", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "DIV23SD02", + "name": "Sub Division Sri Anandpur Sahib", + "hierarchyLevel": 4, + "children": ["905399a1-c1cd-42c1-8c7c-6295aced0952"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "905399a1-c1cd-42c1-8c7c-6295aced0952", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "S557", + "name": "Kiratpur Sahib", + "hierarchyLevel": 5, + "children": ["02c0cb3f-f3e0-4345-a2d4-f64bc27f9cd3", "d77a856e-e637-4ac4-9f77-854b33ee6b6a", "e75e4840-2586-42f8-b8bd-841b8637da06"], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "02c0cb3f-f3e0-4345-a2d4-f64bc27f9cd3", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "7382", + "name": "MASSEWAL", + "hierarchyLevel": 6, + "children": [], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "d77a856e-e637-4ac4-9f77-854b33ee6b6a", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "7402", + "name": "NARD", + "hierarchyLevel": 6, + "children": [], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + }, + { + "_id": "e75e4840-2586-42f8-b8bd-841b8637da06", + "tenantId": "pb", + "departmentId": "b32f0cc1-f4b1-4503-95d6-fdf04d0ea2d4", + "code": "7378", + "name": "MAJHER", + "hierarchyLevel": 6, + "children": [], + "auditDetails": { + "createdBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "lastModifiedBy": "40abff21-9405-4a61-9aa1-d141cb95fb28", + "createdTime": 1629793685000, + "lastModifiedTime": 1629793685000 + }, + "_class" : "org.egov.web.models.DepartmentEntity" + } +]); diff --git a/domain-services/ifix-department-entity-service/src/test/java/org/egov/TestConfiguration.java b/domain-services/ifix-department-entity-service/src/test/java/org/egov/TestConfiguration.java new file mode 100644 index 00000000..d13056a1 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/test/java/org/egov/TestConfiguration.java @@ -0,0 +1,16 @@ +package org.egov; + +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.kafka.core.KafkaTemplate; + +import static org.mockito.Mockito.mock; + +@Configuration +public class TestConfiguration { + @Bean + @SuppressWarnings("unchecked") + public KafkaTemplate kafkaTemplate() { + return mock(KafkaTemplate.class); + } +} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/src/test/java/org/egov/web/controllers/DepartmentEntityApiControllerTest.java b/domain-services/ifix-department-entity-service/src/test/java/org/egov/web/controllers/DepartmentEntityApiControllerTest.java new file mode 100644 index 00000000..47ca30b3 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/test/java/org/egov/web/controllers/DepartmentEntityApiControllerTest.java @@ -0,0 +1,85 @@ +package org.egov.web.controllers; + +import org.egov.TestConfiguration; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; +import org.springframework.context.annotation.Import; +import org.springframework.http.MediaType; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.servlet.MockMvc; + +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +/** + * API tests for DepartmentEntityApiController + */ +@Ignore +@RunWith(SpringRunner.class) +@WebMvcTest(DepartmentEntityApiController.class) +@Import(TestConfiguration.class) +public class DepartmentEntityApiControllerTest { + + @Autowired + private MockMvc mockMvc; + + @Test + public void departmentEntityHierarchyLevelV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/hierarchyLevel/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentEntityHierarchyLevelV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/hierarchyLevel/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void departmentEntityHierarchyLevelV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/hierarchyLevel/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentEntityHierarchyLevelV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/hierarchyLevel/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void departmentEntityV1CreatePostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentEntityV1CreatePostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/v1/_create").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + + @Test + public void departmentEntityV1SearchPostSuccess() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isOk()); + } + + @Test + public void departmentEntityV1SearchPostFailure() throws Exception { + mockMvc.perform(post("/eGovTrial/iFIX-Department-Hierarchy-Master/1.0.0/departmentEntity/v1/_search").contentType(MediaType + .APPLICATION_JSON_UTF8)) + .andExpect(status().isBadRequest()); + } + +} From 3b46cc03d1bc1215f1905313872e9cf8e85b6be4 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:13:22 +0530 Subject: [PATCH 19/67] IFIX-320: New indexes for for fiscal event (#43) * IFIX-320: New indexes for for fiscal event * add department entity id * add ancestry id * IFIX-320: index correction --- .../resources/db/migration/V20210823115500__create_index | 2 +- .../resources/db/migration/V202108310210000__create_index | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) create mode 100644 domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index index 0d1b0b4f..384a6602 100644 --- a/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index +++ b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210823115500__create_index @@ -1,4 +1,4 @@ -db.fiscalEvent.createIndexes( +db.fiscal_event.createIndexes( [{"eventType":1},{"eventTime":1},{"tenantId":1},{"referenceId":1}] ); db.fiscalEvent.getIndexes(); diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index new file mode 100644 index 00000000..b55031c8 --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index @@ -0,0 +1,8 @@ +db.fiscal_event.createIndexes( + [ + {"ingestionTime": 1}, {"departmentEntity.id": 1} ,{"departmentEntity.hierarchyLevel": 1} , {"departmentEntity.code": 1} , {"departmentEntity.name": 1}, + {"departmentEntity.ancestry.id": 1}, {"departmentEntity.ancestry.code": 1}, {"departmentEntity.ancestry.name": 1}, {"departmentEntity.ancestry.hierarchyLevel": 1}, + {"expenditure.id": 1}, {"project.id": 1}, {"parentEventId": 1}, {"amountDetails.coa.id": 1} + ] + ); +db.fiscalEvent.getIndexes(); From 8afc3739de10b8cd0b76d8a61c42880d36cd01cf Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Tue, 31 Aug 2021 17:24:21 +0530 Subject: [PATCH 20/67] IFIX-371 : fiscal event search api (#47) Co-authored-by: pintu-eGov --- domain-services/fiscal-event-service/pom.xml | 5 ++ .../repository/FiscalEventRepository.java | 19 ++++ .../querybuilder/FiscalEventQueryBuilder.java | 32 +++++++ .../org/egov/service/FiscalEventService.java | 42 +++++++++ .../org/egov/util/FiscalEventMapperUtil.java | 89 +++++++++++++++++++ .../org/egov/util/MasterDataConstants.java | 5 ++ .../main/java/org/egov/util/TenantUtil.java | 14 +-- .../egov/validator/FiscalEventValidator.java | 80 ++++++++++++++--- .../web/controllers/FiscalApiController.java | 9 +- .../src/main/resources/application.properties | 4 + 10 files changed, 280 insertions(+), 19 deletions(-) create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/repository/querybuilder/FiscalEventQueryBuilder.java create mode 100644 domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventMapperUtil.java diff --git a/domain-services/fiscal-event-service/pom.xml b/domain-services/fiscal-event-service/pom.xml index c810250d..749fe9fd 100644 --- a/domain-services/fiscal-event-service/pom.xml +++ b/domain-services/fiscal-event-service/pom.xml @@ -74,6 +74,11 @@ javax.validation validation-api + + + org.springframework.boot + spring-boot-starter-data-mongodb + diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java index 5d764384..c345bf6f 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java @@ -2,9 +2,28 @@ import lombok.extern.slf4j.Slf4j; +import org.egov.repository.querybuilder.FiscalEventQueryBuilder; +import org.egov.web.models.Criteria; +import org.egov.web.models.FiscalEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.mongodb.core.MongoTemplate; +import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; +import java.util.List; + @Repository @Slf4j public class FiscalEventRepository { + + @Autowired + private MongoTemplate mongoTemplate; + + @Autowired + private FiscalEventQueryBuilder eventQueryBuilder; + + public List searchFiscalEvent(Criteria searchCriteria) { + Query searchQuery = eventQueryBuilder.buildSearchQuery(searchCriteria); + return (mongoTemplate.find(searchQuery, Object.class,"fiscalEvent")); + } } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/querybuilder/FiscalEventQueryBuilder.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/querybuilder/FiscalEventQueryBuilder.java new file mode 100644 index 00000000..f1e167dc --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/querybuilder/FiscalEventQueryBuilder.java @@ -0,0 +1,32 @@ +package org.egov.repository.querybuilder; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.springframework.data.mongodb.core.query.Criteria; +import org.springframework.data.mongodb.core.query.Query; +import org.springframework.stereotype.Component; + +@Component +@Slf4j +public class FiscalEventQueryBuilder { + + public Query buildSearchQuery(org.egov.web.models.Criteria searchCriteria) { + + Criteria criteria = Criteria.where("tenantId").is(searchCriteria.getTenantId()); + + if (StringUtils.isNotBlank(searchCriteria.getEventType())) + criteria.and("eventType").is(searchCriteria.getEventType()); + + if (searchCriteria.getIds() != null && !searchCriteria.getIds().isEmpty()) + criteria.and("id").in(searchCriteria.getIds()); + + if (searchCriteria.getReferenceId() != null && !searchCriteria.getReferenceId().isEmpty()) + criteria.and("referenceId").in(searchCriteria.getReferenceId()); + + if (searchCriteria.getFromEventTime() != null && searchCriteria.getToEventTime() != null) + criteria.and("eventTime").gte(searchCriteria.getFromEventTime()).lte(searchCriteria.getToEventTime()); + + return new Query(criteria); + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java index 431197d4..1d83752a 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java @@ -1,14 +1,24 @@ package org.egov.service; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.egov.config.FiscalEventConfiguration; import org.egov.producer.Producer; +import org.egov.repository.FiscalEventRepository; +import org.egov.util.FiscalEventMapperUtil; import org.egov.validator.FiscalEventValidator; +import org.egov.web.models.Criteria; +import org.egov.web.models.FiscalEvent; +import org.egov.web.models.FiscalEventGetRequest; import org.egov.web.models.FiscalEventRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.Collections; +import java.util.List; + @Service @Slf4j public class FiscalEventService { @@ -25,6 +35,12 @@ public class FiscalEventService { @Autowired private FiscalEventConfiguration eventConfiguration; + @Autowired + private FiscalEventRepository eventRepository; + + @Autowired + private FiscalEventMapperUtil mapperUtil; + /** * Validate , enrich and push the fiscal Event request to topic @@ -37,4 +53,30 @@ public FiscalEventRequest fiscalEventsV1PushPost(FiscalEventRequest fiscalEventR producer.push(eventConfiguration.getFiscalPushRequest(),fiscalEventRequest); return fiscalEventRequest; } + + /** + * Validate the request, search based on the criteria + * + * @param fiscalEventGetRequest + * @return + */ + public List fiscalEventsV1SearchPost(FiscalEventGetRequest fiscalEventGetRequest) { + validator.validateFiscalEventSearchPost(fiscalEventGetRequest); + Criteria searchCriteria = fiscalEventGetRequest.getCriteria(); + + if ((searchCriteria.getIds() == null || searchCriteria.getIds().isEmpty()) && StringUtils.isBlank(searchCriteria.getEventType()) + && StringUtils.isBlank(searchCriteria.getTenantId()) && searchCriteria.getFromEventTime() == null + && searchCriteria.getToEventTime() == null && (searchCriteria.getReferenceId() == null || searchCriteria.getReferenceId().isEmpty())) { + return Collections.emptyList(); + } + + List dereferencedFiscalEvents = eventRepository.searchFiscalEvent(searchCriteria); + + if (dereferencedFiscalEvents == null || dereferencedFiscalEvents.isEmpty()) + return Collections.emptyList(); + + List fiscalEvents = mapperUtil.mapDereferencedFiscalEventToFiscalEvent(dereferencedFiscalEvents); + + return fiscalEvents; + } } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventMapperUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventMapperUtil.java new file mode 100644 index 00000000..1d3aecca --- /dev/null +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventMapperUtil.java @@ -0,0 +1,89 @@ +package org.egov.util; + + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.web.models.Amount; +import org.egov.web.models.FiscalEvent; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; +import java.util.List; + +@Component +@Slf4j +public class FiscalEventMapperUtil { + + @Autowired + private ObjectMapper objectMapper; + + /** + * @param dereferencedFiscalEvents + * @return + */ + public List mapDereferencedFiscalEventToFiscalEvent(List dereferencedFiscalEvents) { + if (dereferencedFiscalEvents == null || dereferencedFiscalEvents.isEmpty()) + Collections.emptyList(); + JsonNode dereferencedFiscalEventNode = objectMapper.convertValue(dereferencedFiscalEvents, JsonNode.class); + Iterator nodeIterator = dereferencedFiscalEventNode.iterator(); + List fiscalEvents = new ArrayList<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + fiscalEvents.add(getFiscalEvent(node)); + } + return fiscalEvents; + } + + private FiscalEvent getFiscalEvent(JsonNode node) { + FiscalEvent fiscalEvent = FiscalEvent.builder() + .id(node.get("_id").asText()) + .tenantId(node.get("tenantId") != null ? node.get("tenantId").asText() : null) + .eventType(node.get("eventType") != null ? FiscalEvent.EventTypeEnum.valueOf(node.get("eventType").asText()) : null) + .eventTime(node.get("eventTime") != null ? node.get("eventTime").asLong() : null) + .referenceId(node.get("referenceId") != null ? node.get("referenceId").asText() : null) + .parentReferenceId(node.get("parentReferenceId") != null ? node.get("parentReferenceId").asText() : null) + .parentEventId(node.get("parentEventId") != null ? node.get("parentEventId").asText() : null) + .ingestionTime(node.get("ingestionTime") != null ? node.get("ingestionTime").asLong() : null) + .attributes(node.get("attributes")) + .build(); + + //audit details + if (node.get("auditDetails") != null) { + AuditDetails auditDetails = AuditDetails.builder() + .createdBy(node.get("auditDetails").get("createdBy") != null ? node.get("auditDetails").get("createdBy").asText() : null) + .lastModifiedBy(node.get("auditDetails").get("lastModifiedBy") != null ? node.get("auditDetails").get("lastModifiedBy").asText() : null) + .createdTime(node.get("auditDetails").get("createdTime") != null ? node.get("auditDetails").get("createdTime").asLong() : null) + .lastModifiedTime(node.get("auditDetails").get("lastModifiedTime") != null ? node.get("auditDetails").get("lastModifiedTime").asLong() : null) + .build(); + fiscalEvent.setAuditDetails(auditDetails); + } + //Amount Details + if (node.get("amountDetails") != null && !node.get("amountDetails").isEmpty()) { + List amountDetails = new ArrayList<>(); + Iterator amtIterator = node.get("amountDetails").iterator(); + while (amtIterator.hasNext()) { + JsonNode amountNode = amtIterator.next(); + Amount amount = Amount.builder() + .id(amountNode.get("id") != null ? amountNode.get("id").asText() : null) + .amount(amountNode.get("amount") != null ? amountNode.get("amount").decimalValue() : null) + .coaId(amountNode.get("coa") != null && amountNode.get("coa").get("id") != null ? amountNode.get("coa").get("id").asText() : null) + .fromBillingPeriod(amountNode.get("fromBillingPeriod") != null ? amountNode.get("fromBillingPeriod").asLong() : null) + .toBillingPeriod(amountNode.get("toBillingPeriod") != null ? amountNode.get("toBillingPeriod").asLong() : null) + .build(); + + amountDetails.add(amount); + } + fiscalEvent.setAmountDetails(amountDetails); + } + //project + if (node.get("project") != null && node.get("project").get("id") != null) { + fiscalEvent.setProjectId(node.get("project").get("id").asText()); + } + return fiscalEvent; + } +} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java index be7ec835..3a444982 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -6,6 +6,9 @@ public class MasterDataConstants { public static final String FISCAL_EVENT = "FISCAL_EVENT"; public static final String REFERENCE_ID = "REFERENCE_ID"; public static final String EVENT_TYPE = "EVENT_TYPE"; + public static final String TO_EVENT_TIME = "TO_EVENT_TIME"; + public static final String FROM_EVENT_TIME = "FROM_EVENT_TIME"; + public static final String PARENT_EVENT_ID = "PARENT_EVENT_ID"; private MasterDataConstants() { } @@ -26,5 +29,7 @@ private MasterDataConstants() { public static final String PROJECT_LIST = "$.project.*"; public static final String COA_IDS_JSON_PATH = "$.chartOfAccounts.*.id"; + public static final String SEARCH_CRITERIA = "SEARCH_CRITERIA"; + } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java index edb48d6b..910d45ba 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java @@ -24,20 +24,20 @@ public class TenantUtil { ServiceRequestRepository serviceRequestRepository; /** - * @param fiscalEventRequest + * + * @param tenantId + * @param requestHeader * @return */ - public boolean validateTenant(FiscalEventRequest fiscalEventRequest) { - if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null - && fiscalEventRequest.getFiscalEvent() != null - && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getTenantId())) { + public boolean validateTenant(String tenantId, RequestHeader requestHeader) { + if (StringUtils.isNotBlank(tenantId) && requestHeader != null) { Map tenantValueMap = new HashMap<>(); tenantValueMap.put(MasterDataConstants.IDS, - Collections.singletonList(fiscalEventRequest.getFiscalEvent().getTenantId())); + Collections.singletonList(tenantId)); Map tenantMap = new HashMap<>(); - tenantMap.put(MasterDataConstants.REQUEST_HEADER, fiscalEventRequest.getRequestHeader()); + tenantMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); tenantMap.put(MasterDataConstants.CRITERIA, tenantValueMap); Object response = serviceRequestRepository.fetchResult(createSearchTenantUrl(), tenantMap); diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index 4ea11a0a..0977d6fc 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -5,22 +5,17 @@ import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.FiscalEventRepository; import org.egov.tracer.model.CustomException; +import org.egov.util.CoaUtil; import org.egov.util.MasterDataConstants; import org.egov.util.ProjectUtil; import org.egov.util.TenantUtil; -import org.egov.util.CoaUtil; -import org.egov.web.models.Amount; -import org.egov.web.models.FiscalEvent; -import org.egov.web.models.FiscalEventRequest; +import org.egov.web.models.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.HashMap; -import java.util.Map; - -import java.util.ArrayList; -import java.util.List; +import java.util.*; @Component @Slf4j @@ -36,6 +31,9 @@ public class FiscalEventValidator { @Autowired ProjectUtil projectUtil; + @Autowired + private FiscalEventRepository eventRepository; + /** * Validate the fiscal Event request * @@ -61,6 +59,7 @@ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { validateTenantId(fiscalEventRequest, errorMap); validateProjectId(fiscalEventRequest, errorMap); validateFiscalEventAmountDetails(fiscalEventRequest, errorMap); + validateParentEventId(fiscalEventRequest,errorMap); if (!errorMap.isEmpty()) { throw new CustomException(errorMap); @@ -71,6 +70,21 @@ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { } } + private void validateParentEventId(FiscalEventRequest fiscalEventRequest, Map errorMap) { + if (StringUtils.isNotBlank(fiscalEventRequest.getFiscalEvent().getParentEventId()) + && StringUtils.isNotBlank(fiscalEventRequest.getFiscalEvent().getTenantId())) { + Criteria criteria = new Criteria(); + + criteria.setTenantId(fiscalEventRequest.getFiscalEvent().getTenantId()); + criteria.setIds(Collections.singletonList(fiscalEventRequest.getFiscalEvent().getParentEventId())); + + List fiscalEventList = eventRepository.searchFiscalEvent(criteria); + if (fiscalEventList == null || fiscalEventList.isEmpty()) + errorMap.put(MasterDataConstants.PARENT_EVENT_ID, "Parent event id doesn't exist in the system."); + + } + } + /** * Validate the request header * @@ -128,8 +142,13 @@ private void validateFiscalEventAmountDetails(FiscalEventRequest fiscalEventRequ * @param fiscalEventRequest */ public void validateTenantId(FiscalEventRequest fiscalEventRequest, Map errorMap) { - boolean isValidTenant = tenantUtil.validateTenant(fiscalEventRequest); - + if(StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getTenantId())){ + errorMap.put(MasterDataConstants.TENANT_ID,"Tenant id is missing in request"); + } + boolean isValidTenant = false; + if (fiscalEventRequest.getFiscalEvent() != null && StringUtils.isNotBlank(fiscalEventRequest.getFiscalEvent().getTenantId())) { + isValidTenant = tenantUtil.validateTenant(fiscalEventRequest.getFiscalEvent().getTenantId(), fiscalEventRequest.getRequestHeader()); + } if (!isValidTenant) { errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id doesn't exist in the system"); } @@ -146,4 +165,43 @@ public void validateProjectId(FiscalEventRequest fiscalEventRequest, Map errorMap = new HashMap<>(); + + //validation : tenant id + if (StringUtils.isBlank(criteria.getTenantId())) + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is missing in request"); + boolean isValidTenant = false; + if (StringUtils.isNotBlank(criteria.getTenantId())) { + isValidTenant = tenantUtil.validateTenant(criteria.getTenantId(), requestHeader); + } + if (!isValidTenant) + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id doesn't exist in the system"); + + //validation : event type + if (StringUtils.isBlank(criteria.getEventType())) + errorMap.put(MasterDataConstants.EVENT_TYPE, "Event type is missing in request"); + + //validation : fromEventTime and toEventTime + if (criteria.getFromEventTime() != null) { + if (criteria.getToEventTime() == null) { + errorMap.put(MasterDataConstants.TO_EVENT_TIME, "To(End) event time is missing for given From(start) event time in request."); + } + } + if (criteria.getToEventTime() != null) { + if (criteria.getFromEventTime() == null) { + errorMap.put(MasterDataConstants.FROM_EVENT_TIME, "From(start) event time is missing for given To(End) event time in request."); + } + } + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java index 9a2f1480..5ded5baa 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java @@ -5,6 +5,7 @@ import io.swagger.annotations.ApiParam; import org.egov.common.contract.response.ResponseHeader; import org.egov.util.ResponseHeaderCreator; +import org.egov.web.models.FiscalEvent; import org.egov.web.models.FiscalEventGetRequest; import org.egov.web.models.FiscalEventRequest; import org.egov.web.models.FiscalEventResponse; @@ -20,6 +21,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.util.Collections; +import java.util.List; @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-09T17:28:42.515+05:30") @@ -54,7 +56,12 @@ public ResponseEntity fiscalEventsV1PushPost(@ApiParam(valu @RequestMapping(value = "/_search", method = RequestMethod.POST) public ResponseEntity fiscalEventsV1SearchPost(@ApiParam(value = "RequestHeader meta data.", required = true) @Valid @RequestBody FiscalEventGetRequest body) { - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + List fiscalEventList = fiscalEventService.fiscalEventsV1SearchPost(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + FiscalEventResponse fiscalEventResponse = FiscalEventResponse.builder().responseHeader(responseHeader) + .fiscalEvent(fiscalEventList).build(); + + return new ResponseEntity(fiscalEventResponse, HttpStatus.OK); } } diff --git a/domain-services/fiscal-event-service/src/main/resources/application.properties b/domain-services/fiscal-event-service/src/main/resources/application.properties index 23a7021b..5047a789 100644 --- a/domain-services/fiscal-event-service/src/main/resources/application.properties +++ b/domain-services/fiscal-event-service/src/main/resources/application.properties @@ -25,6 +25,10 @@ spring.kafka.producer.value-serializer=org.springframework.kafka.support.seriali #kafka.producer.config.linger_ms_config=1 #kafka.producer.config.buffer_memory_config=33554432 +#mongoDB +spring.data.mongodb.uri=mongodb://localhost:27017/?retryWrites=false +spring.data.mongodb.database=ifix_dev_db + ## Kafka Topic Configurations ## fiscal.kafka.push.topic=fiscal-event-request-validated From a869bd533b99b64ec51c53b494b298841a3f6f20 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 1 Sep 2021 09:17:30 +0530 Subject: [PATCH 21/67] Jmeter test plan for fiscal-event-service (#48) Co-authored-by: rushang7-eGov --- .../Fiscal-Event-Request.jmx | 171 ++++++++++++++++++ 1 file changed, 171 insertions(+) create mode 100644 domain-services/fiscal-event-service/Fiscal-Event-Request.jmx diff --git a/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx b/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx new file mode 100644 index 00000000..d8063fe6 --- /dev/null +++ b/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx @@ -0,0 +1,171 @@ + + + + + + false + true + false + + + + + + + + continue + + false + -1 + + 250 + 60 + false + + + true + + + + true + + + + false + { + "requestHeader": { + "ts": 1629286294000, + "version": "v1", + "msgId": "", + "signature": "", + "userInfo": { + "uuid": "e4fd96e8-3b6b-4e36-9503-0f14a01af39d" + } + }, + "fiscalEvent": { + "tenantId": "pb", + "projectId": "74c62227-d91a-4301-9592-2c9178af002d", + "eventType": "RECEIPT", + "referenceId": "8fade363-0ee6-46cb-a3ab-90e852f2de0d", + "eventTime": "1603423893000", + "amountDetails": [ + { + "amount": 540, + "fromBillingPeriod": "1609459693000", + "toBillingPeriod": "1599400181000", + "coaId": "23d38475-80a4-486d-9946-da890e165dfa" + } + ] + } +} + = + + + + ifix-dev.ifix.org.in + + https + + /fiscal-event-service/events/v1/_push + POST + true + false + true + false + + + + + + + + + Content-Type + application/json + + + Authorization + Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzIzMDQ4NjcsImlhdCI6MTYyOTcxMjg2NywianRpIjoiYzM5MmRkODctNWI4MC00ZjVkLWIxNGQtNjk3ZDExNGEzNWUzIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.Hby4BbwMvecANTo-JOefpaaNhNEw1YxcCRfc8bCNxzr49PZLiz7RZZx5f11Df4ifSMErQBtyr6Xb_PDyQXtvJl10BHofznf-dciyVDIDy6uJgzUhXZJTQq6aZFIgO-WEsDvfCFuBEEoLrxB3vl5L8fATRqS3g1TEItp_uq5tKleCl05vH96MuR1soOZjH-ow6qZMSRspqU0jGwbeG-SCyMFfFWD-z123LRrXy4psTmUv4v0d4Z7QHfonctjA3Bo99uQ6GUAQ8QhgBWkwpG5hj4x8y6ZAbeCUP-LgNvXQKSms1qvsteGsGaaNuUco-jqxK7fsMVpJ69RzCCNDmFZByA + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + false + + saveConfig + + + true + true + true + + true + true + true + true + false + true + true + false + false + false + true + false + false + false + true + 0 + true + true + true + true + true + true + + + + + + + + + + From 6c1e7b7a11e3ed24af68ed8fc67a50a31a82dad4 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 1 Sep 2021 09:56:17 +0530 Subject: [PATCH 22/67] Updated README file (#49) * Updated README file * README changes --- .../ifix-department-entity-service/README.md | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/domain-services/ifix-department-entity-service/README.md b/domain-services/ifix-department-entity-service/README.md index ad48c27a..848d9d51 100644 --- a/domain-services/ifix-department-entity-service/README.md +++ b/domain-services/ifix-department-entity-service/README.md @@ -1 +1,28 @@ -# iFIX-Department-Entity-Service \ No newline at end of file +# iFIX-Department-Entity-Service + +## Department Hierarchy +It defines hierarchy definition for department. + +**department id:** It is master department id (UUID).\ +**level:** It defines the depth of hierarchy of department level.\ +**parent:** It provides details about department parent (UUID). + +Root level department hierarchy will not contain any parent value and level value will be zero.\ +Level value incrementation rule: +1. When parent id is having any value then we search parent in department hierarchy record for hierarchy level evaluation. +2. Get level value from parent department hierarchy and increment current department hierarchy level value by one. + + +## Department Entity +It contains department entity information along with its hierarchy level and also attaches master department information (department id - UUID). +Here we keep all children information list at every department node (department record). +Leaf level department will not have any children info. + +Children list contains department entity id list, which makes current department entity parent of all children list (department id list), that's how it maintains department entity level. + +### Entities creation approaches +1. First we need to define the hierarchy level top to bottom because it has parent's reference. +2. Only then we can start adding department entities, bottom-to-top because it has child's reference. + +_**Note**: The root department hierarchy will have the label "Department", and the root department entity will be the +department itself._ From d954343b9129c4a0b35929c8933ce7c042665b06 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 1 Sep 2021 11:00:13 +0530 Subject: [PATCH 23/67] Migration file rename (#50) --- ...02108310210000__create_index => V20210831021000__create_index} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename domain-services/fiscal-event-service/src/main/resources/db/migration/{V202108310210000__create_index => V20210831021000__create_index} (100%) diff --git a/domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index b/domain-services/fiscal-event-service/src/main/resources/db/migration/V20210831021000__create_index similarity index 100% rename from domain-services/fiscal-event-service/src/main/resources/db/migration/V202108310210000__create_index rename to domain-services/fiscal-event-service/src/main/resources/db/migration/V20210831021000__create_index From 2371d5424512552026d98672ccd4e6da1fac47c5 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 1 Sep 2021 11:00:57 +0530 Subject: [PATCH 24/67] Update INSTRUCTIONS.md (#51) Co-authored-by: rushang7-eGov --- core/keycloak/INSTRUCTIONS.md | 35 ++++++++++++++++++++--------------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/core/keycloak/INSTRUCTIONS.md b/core/keycloak/INSTRUCTIONS.md index 508702af..8eca3f25 100644 --- a/core/keycloak/INSTRUCTIONS.md +++ b/core/keycloak/INSTRUCTIONS.md @@ -1,25 +1,30 @@ # Keycloak Setup +Keycloak console would be available at `https:///auth`. Please get the username and password secrets from the Ops team. + ## Import Realm -1. Open the keycloak console +1. Open the Keycloak console 2. Near the top-left corner in the realm drop down menu, select **Add Realm**. 3. Select the [ifix-realm.json](./ifix-realm.json) file. +4. After the realm gets created, select the `ifix` realm from the drop-down near the top-left corner. ## Creating Clients -1. From the Clients section of Keycloak Admin Console, create a client. -2. Provide unique username for the client. -3. Go to client's settings -4. Change Access Type to **confidential** -5. Turn on **Service Account Enabled** -6. In the **Valid Redirect URIs** field provide the root url of the iFIX Instance. (Not important for our purposes but need to set it because it is mandatory) -7. And Save these changes -8. In the **Service Account Roles** tab, assign the role "fiscal-event-producer" -9. In the **Mappers** tab, create a new mapper to associate the client with a tenantId - a. Select Mapper Type to be Hardcoded claim - b. In Claim Name, write "tenantId" - c. In Claim value, write the under which the client is being created. (For example, "pb") - d. Select Claim Json Type to be String +1. Remember to select the `ifix` realm from the Keycloak console before proceeding. +2. From the Clients section of Keycloak Admin Console, create a client. +3. Provide unique username for the client. +4. Go to client's settings +5. Change Access Type to **confidential** +6. Turn on **Service Account Enabled** +7. In the **Valid Redirect URIs** field provide the root url of the iFIX Instance. (Not important for our purposes but need to set it because it is mandatory) +8. And Save these changes +9. In the **Service Account Roles** tab, assign the role "fiscal-event-producer" +10. In the **Mappers** tab, create a new mapper to associate the client with a tenantId + 1. Select `Mapper Type` to be "Hardcoded claim" + 2. In `Token Claim Name`, write "tenantId" + 3. In `Claim value`, write the under which the client is being created. (For example, "pb") + 4. Set `Name` same as `Token Claim Name` i.e. "tenantId" + 5. Select `Claim Json Type` to be "String" -Now you can get the credentials from the **Credentials** tab and configure them in the client's system. \ No newline at end of file +Now you can get the credentials from the **Credentials** tab and configure them in the client's system. From 60e7f4fda3e3127ee62994ca750ec357ee39cfd3 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Thu, 2 Sep 2021 13:31:41 +0530 Subject: [PATCH 25/67] Pk ifix 319 (#52) * IFIX 319 : Create expenditure api * IFIX-318: Department Entity create Co-authored-by: pintu-eGov --- .../MasterDataServiceConfiguration.java | 9 ++ .../egov/repository/DepartmentRepository.java | 7 ++ .../repository/ExpenditureRepository.java | 4 + .../service/DepartmentEnrichmentService.java | 31 ++++++- .../org/egov/service/DepartmentService.java | 13 +++ .../service/ExpenditureEnrichmentService.java | 36 ++++++++ .../org/egov/service/ExpenditureService.java | 10 ++ .../org/egov/util/MasterDataConstants.java | 6 ++ .../org/egov/util/MasterDepartmentUtil.java | 71 ++++++++++++++ .../validator/ChartOfAccountValidator.java | 10 +- .../egov/validator/DepartmentValidator.java | 58 +++++++++++- .../egov/validator/ExpenditureValidator.java | 92 ++++++++++++++++++- .../egov/validator/GovernmentValidator.java | 18 ++-- .../org/egov/validator/ProjectValidator.java | 3 + .../controllers/DepartmentApiController.java | 17 +++- .../controllers/ExpenditureApiController.java | 15 ++- .../java/org/egov/web/models/Expenditure.java | 4 +- .../src/main/resources/application.properties | 4 + 18 files changed, 379 insertions(+), 29 deletions(-) create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureEnrichmentService.java create mode 100644 domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDepartmentUtil.java diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java index 4e38b9b0..b5d9e4b9 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/config/MasterDataServiceConfiguration.java @@ -53,4 +53,13 @@ public void initialize() { @Value("${ifix.department.entity.search.path}") private String departmentEntitySearchPath; + @Value("${ifix.master.department.host}") + private String ifixMasterDepartmenteHost; + + @Value("${ifix.master.department.context.path}") + private String ifixMasterDepartmentContextPath; + + @Value("${ifix.master.department.search.path}") + private String ifixMasterDepartmentSearchPath; + } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java index c5c3b2f4..04fd22a7 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java @@ -28,4 +28,11 @@ public List search(DepartmentSearchCriteria searchCriteria) { Query searchQuery = departmentQueryBuilder.buildSearchQuery(searchCriteria); return (mongoTemplate.find(searchQuery, Department.class)); } + + /** + * @param department + */ + public void save(Department department) { + mongoTemplate.save(department); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java index 5ea9a57e..2d1eaad2 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ExpenditureRepository.java @@ -25,4 +25,8 @@ public class ExpenditureRepository { public List findAllByCriteria(ExpenditureSearchCriteria expenditureSearchCriteria) { return mongoTemplate.find(expenditureQueryBuilder.buildQuerySearch(expenditureSearchCriteria), Expenditure.class); } + + public void save(Expenditure expenditure) { + mongoTemplate.save(expenditure); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java index 1c88d8e4..cb93f4a4 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java @@ -2,14 +2,22 @@ import lombok.extern.slf4j.Slf4j; -import org.egov.web.models.DepartmentSearchCriteria; -import org.egov.web.models.DepartmentSearchRequest; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.MasterDataServiceUtil; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.UUID; + @Service @Slf4j public class DepartmentEnrichmentService { + @Autowired + MasterDataServiceUtil enrichAuditDetails; + /** * Enrich the department search request * @param searchRequest @@ -19,4 +27,23 @@ public void enrichSearchPost(DepartmentSearchRequest searchRequest) { //TODO- fill if any default search criteria } + + /** + * @param departmentRequest + */ + public void enrichDepartmentData(DepartmentRequest departmentRequest) { + Department department = departmentRequest.getDepartment(); + RequestHeader requestHeader = departmentRequest.getRequestHeader(); + + AuditDetails auditDetails = null; + + if(department.getAuditDetails() == null){ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), department.getAuditDetails(), true); + }else{ + auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), department.getAuditDetails(), false); + } + + department.setId(UUID.randomUUID().toString()); + department.setAuditDetails(auditDetails); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java index f622a9c8..23d6fca0 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentService.java @@ -5,6 +5,7 @@ import org.egov.repository.DepartmentRepository; import org.egov.validator.DepartmentValidator; import org.egov.web.models.Department; +import org.egov.web.models.DepartmentRequest; import org.egov.web.models.DepartmentSearchCriteria; import org.egov.web.models.DepartmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; @@ -47,4 +48,16 @@ public List departmentV1SearchPost(DepartmentSearchRequest searchReq return departments; } + + /** + * @param departmentRequest + * @return + */ + public DepartmentRequest createDepartment(DepartmentRequest departmentRequest) { + validator.validateCreateRequestData(departmentRequest); + enricher.enrichDepartmentData(departmentRequest); + departmentRepo.save(departmentRequest.getDepartment()); + + return departmentRequest; + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureEnrichmentService.java new file mode 100644 index 00000000..e76222f8 --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureEnrichmentService.java @@ -0,0 +1,36 @@ +package org.egov.service; + + +import lombok.extern.slf4j.Slf4j; +import org.egov.common.contract.AuditDetails; +import org.egov.common.contract.request.RequestHeader; +import org.egov.util.MasterDataServiceUtil; +import org.egov.web.models.Expenditure; +import org.egov.web.models.ExpenditureRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +import java.util.UUID; + +@Service +@Slf4j +public class ExpenditureEnrichmentService { + + @Autowired + private MasterDataServiceUtil mdsUtil; + + public void enrichCreateExpenditure(ExpenditureRequest expenditureRequest) { + Expenditure expenditure = expenditureRequest.getExpenditure(); + RequestHeader requestHeader = expenditureRequest.getRequestHeader(); + + AuditDetails auditDetails = null; + if (expenditure.getAuditDetails() == null) { + auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), expenditure.getAuditDetails(), true); + } else { + auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), expenditure.getAuditDetails(), false); + } + + expenditure.setAuditDetails(auditDetails); + expenditure.setId(UUID.randomUUID().toString()); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java index 1623756e..b6ba263f 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ExpenditureService.java @@ -3,6 +3,7 @@ import org.egov.repository.ExpenditureRepository; import org.egov.validator.ExpenditureValidator; import org.egov.web.models.Expenditure; +import org.egov.web.models.ExpenditureRequest; import org.egov.web.models.ExpenditureSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -18,6 +19,9 @@ public class ExpenditureService { @Autowired ExpenditureValidator expenditureValidator; + @Autowired + private ExpenditureEnrichmentService enricher; + /** * @param expenditureSearchRequest * @return @@ -27,4 +31,10 @@ public List findAllByCriteria(ExpenditureSearchRequest expenditureS return expenditureRepository.findAllByCriteria(expenditureSearchRequest.getCriteria()); } + public ExpenditureRequest createV1Expenditure(ExpenditureRequest expenditureRequest) { + expenditureValidator.validateExpenditureCreateRequest(expenditureRequest); + enricher.enrichCreateExpenditure(expenditureRequest); + expenditureRepository.save(expenditureRequest.getExpenditure()); + return expenditureRequest; + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java index ddbc8db2..66d53dec 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -16,6 +16,7 @@ private MasterDataConstants() { public static final String TENANT_ID = "TENANT_ID"; public static final String EXPENDITURE_NAME = "EXPENDITURE_NAME"; public static final String EXPENDITURE_CODE = "EXPENDITURE_CODE"; + public static final String EXPENDITURE_TYPE = "EXPENDITURE_TYPE"; public static final String REQUEST_PAYLOAD_MISSING = "REQUEST_PAYLOAD"; public static final String PROJECT_NAME = "PROJECT_NAME"; @@ -29,11 +30,16 @@ private MasterDataConstants() { public static final String TENANT_LIST = "$.government.*"; public static final String EXPENDITURE_LIST = "$.expenditure.*"; public static final String DEPARTMENT_ENTITY_LIST = "$.departmentEntity.*"; + public static final String DEPARTMENT_JSON_PATH = "$.department.*"; public static final String DEPARTMENT_ENTITY_ID = "DEPARTMENT_ENTITY_ID"; public static final String JSONPATH_ERROR = "JSONPATH_ERROR"; public static final String GET_ANCESTRY = "getAncestry"; + public static final String REQUEST_HEADER_MISSING = "REQUEST_HEADER"; + public static final String DEPARTMENT_CODE = "DEPARTMENT_CODE"; + public static final String DEPARTMENT_NAME = "DEPARTMENT_NAME"; + public static final String DEPARTMENT_PARENT = "DEPARTMENT_PARENT"; } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDepartmentUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDepartmentUtil.java new file mode 100644 index 00000000..55b6fdfd --- /dev/null +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDepartmentUtil.java @@ -0,0 +1,71 @@ +package org.egov.util; + + +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.jayway.jsonpath.JsonPath; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.common.contract.request.RequestHeader; +import org.egov.config.MasterDataServiceConfiguration; +import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.web.models.Department; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +@Component +@Slf4j +public class MasterDepartmentUtil { + + @Autowired + private MasterDataServiceConfiguration configuration; + + @Autowired + private ServiceRequestRepository searchRequestRepository; + + @Autowired + private ObjectMapper objectMapper; + + /** + * @param departmentIds + * @param tenantId + * @param requestHeader + * @return + */ + public List fetchDepartment(List departmentIds, String tenantId, RequestHeader requestHeader) { + if ((departmentIds != null && !departmentIds.isEmpty()) && StringUtils.isNotBlank(tenantId) && requestHeader != null) { + Map departmentValueMap = new HashMap<>(); + departmentValueMap.put(MasterDataConstants.IDS, departmentIds); + departmentValueMap.put(MasterDataConstants.CRITERIA_TENANT_ID, tenantId); + + Map departmentMap = new HashMap<>(); + departmentMap.put(MasterDataConstants.REQUEST_HEADER, requestHeader); + departmentMap.put(MasterDataConstants.CRITERIA, departmentValueMap); + + Object response = searchRequestRepository.fetchResult(createSearchDepartmentUrl(), departmentMap); + try { + List departmentList = JsonPath.read(response, MasterDataConstants.DEPARTMENT_JSON_PATH); + + return objectMapper.convertValue(departmentList, new TypeReference>() { + }); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse expenditure response"); + } + } + return Collections.emptyList(); + } + + private String createSearchDepartmentUrl() { + StringBuilder uriBuilder = new StringBuilder(); + uriBuilder.append(configuration.getIfixMasterDepartmenteHost()) + .append(configuration.getIfixMasterDepartmentContextPath()) + .append(configuration.getIfixMasterDepartmentSearchPath()); + return uriBuilder.toString(); + } +} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java index de4718af..72198140 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java @@ -7,6 +7,7 @@ import org.egov.repository.ChartOfAccountRepository; import org.egov.tracer.model.CustomException; import org.egov.util.CoaUtil; +import org.egov.util.MasterDataConstants; import org.egov.web.models.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -44,6 +45,13 @@ public void validateCreatePost(COARequest coaRequest) { throw new CustomException("INVALID_REQUEST", "COA request is invalid"); } + //Tenant id validation + if (StringUtils.isBlank(chartOfAccount.getTenantId())) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is mandatory"); + } + if (StringUtils.isNotBlank(chartOfAccount.getTenantId()) + && (chartOfAccount.getTenantId().length() < 2 || chartOfAccount.getTenantId().length() > 64)) + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id's length is invalid"); //code validation if (StringUtils.isBlank(chartOfAccount.getGroupHead())) { throw new CustomException("GROUP_HEAD", "Group head Code is mandatory for chart of account"); @@ -117,7 +125,7 @@ public void validateCreatePost(COARequest coaRequest) { //call the Tenant Service for search, if doesn't exist add in the error map List governments = coaUtil.searchTenants(requestHeader, chartOfAccount); if (governments == null || governments.isEmpty()) { - errorMap.put("TENANT_ID", "Tenant id doesn't exist in the system"); + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id doesn't exist in the system"); } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java index cd813a10..926329d0 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java @@ -5,8 +5,10 @@ import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; import org.egov.tracer.model.CustomException; -import org.egov.web.models.DepartmentSearchCriteria; -import org.egov.web.models.DepartmentSearchRequest; +import org.egov.util.MasterDataConstants; +import org.egov.util.TenantUtil; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.HashMap; @@ -16,6 +18,8 @@ @Slf4j public class DepartmentValidator { + @Autowired + private TenantUtil tenantUtil; /** * Validate the department search attribute(s) @@ -63,4 +67,54 @@ public void validateSearchPost(DepartmentSearchRequest searchRequest) { if (!errorMap.isEmpty()) throw new CustomException(errorMap); } + + /** + * @param departmentRequest + */ + public void validateCreateRequestData(DepartmentRequest departmentRequest) { + Map errorMap = new HashMap<>(); + + if (departmentRequest != null && departmentRequest.getDepartment() != null + && departmentRequest.getRequestHeader() != null) { + RequestHeader requestHeader = departmentRequest.getRequestHeader(); + + if (requestHeader.getUserInfo() == null || StringUtils.isEmpty(requestHeader.getUserInfo().getUuid())) { + errorMap.put(MasterDataConstants.USER_INFO, "User information is missing"); + } + + Department department = departmentRequest.getDepartment(); + + if (StringUtils.isEmpty(department.getTenantId())) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); + } else if (department.getTenantId().length() < 2 || department.getTenantId().length() > 64) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + } else if (!tenantUtil.validateTenant(department.getTenantId(), requestHeader)) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id : " + department.getTenantId() + + " doesn't exist in the system"); + } + + if (StringUtils.isEmpty(department.getCode())) { + errorMap.put(MasterDataConstants.DEPARTMENT_CODE, "Department code is missing in request data"); + }else if (department.getCode().length() < 1 || department.getCode().length() > 64) { + errorMap.put(MasterDataConstants.DEPARTMENT_CODE, "Department code length is invalid. " + + "Length range [1-64]"); + } + + if (StringUtils.isEmpty(department.getCode())) { + errorMap.put(MasterDataConstants.DEPARTMENT_NAME, "Department name is missing in request data"); + }else if (department.getCode().length() < 1 || department.getCode().length() > 64) { + errorMap.put(MasterDataConstants.DEPARTMENT_NAME, "Department name length is invalid. " + + "Length range [1-64]"); + } + + if (StringUtils.isNotBlank(department.getParent()) + && (department.getParent().length() < 2 || department.getParent().length() > 64)) + errorMap.put(MasterDataConstants.DEPARTMENT_PARENT, "Department parent length is invalid. " + + "Length range [1-64]"); + } + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java index 3b9aa63d..a4e7e7af 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java @@ -1,16 +1,31 @@ package org.egov.validator; +import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; import org.egov.tracer.model.CustomException; import org.egov.util.MasterDataConstants; -import org.egov.web.models.ExpenditureSearchCriteria; -import org.egov.web.models.ExpenditureSearchRequest; +import org.egov.util.MasterDepartmentUtil; +import org.egov.util.TenantUtil; +import org.egov.web.models.*; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + @Component +@Slf4j public class ExpenditureValidator { + @Autowired + private TenantUtil tenantUtil; + + @Autowired + private MasterDepartmentUtil masterDepartmentUtil; + public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditureSearchRequest) { if (expenditureSearchRequest != null || expenditureSearchRequest.getRequestHeader() == null && expenditureSearchRequest.getCriteria() != null) { @@ -25,9 +40,7 @@ public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditur if (StringUtils.isEmpty(criteria.getTenantId())) { throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); - } - - if (criteria.getTenantId().length() < 2 || criteria.getTenantId().length() > 64) { + }else if (criteria.getTenantId().length() < 2 || criteria.getTenantId().length() > 64) { throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + "Length range [2-64]"); } @@ -48,4 +61,73 @@ public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditur throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } } + + public void validateExpenditureCreateRequest(ExpenditureRequest expenditureRequest) { + RequestHeader requestHeader = expenditureRequest.getRequestHeader(); + Expenditure expenditure = expenditureRequest.getExpenditure(); + Map errorMap = new HashMap<>(); + + //Header validation + if (requestHeader == null) { + throw new CustomException(MasterDataConstants.REQUEST_HEADER_MISSING, "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put(MasterDataConstants.USER_INFO, "User info is missing"); + } + + if (expenditure == null) { + throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Expenditure request is invalid"); + } + + //Tenant id + if (StringUtils.isBlank(expenditure.getTenantId())) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is mandatory"); + } + if (StringUtils.isNotBlank(expenditure.getTenantId()) + && (expenditure.getTenantId().length() < 2 || expenditure.getTenantId().length() > 64)) { + throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + + "Length range [2-64]"); + } + if (StringUtils.isNotBlank(expenditure.getTenantId())) { + boolean isValidTenantId = tenantUtil.validateTenant(expenditure.getTenantId(), requestHeader); + if (!isValidTenantId) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id doesn't exist in the system"); + } + } + + //code + if (StringUtils.isBlank(expenditure.getCode())) { + errorMap.put(MasterDataConstants.EXPENDITURE_CODE, "Expenditure code is missing in request data"); + } + if (StringUtils.isNotBlank(expenditure.getCode()) + && (expenditure.getCode().length() < 2 || expenditure.getCode().length() > 64)) { + errorMap.put(MasterDataConstants.EXPENDITURE_CODE, "Expenditure code length is invalid. " + + "Length range [2-64]"); + } + + //name + if (StringUtils.isBlank(expenditure.getName())) { + errorMap.put(MasterDataConstants.EXPENDITURE_NAME, "Expenditure name is missing in request data"); + } + if (StringUtils.isNotBlank(expenditure.getName()) + && (expenditure.getName().length() < 2 || expenditure.getName().length() > 256)) { + errorMap.put(MasterDataConstants.EXPENDITURE_NAME, "Expenditure name length is invalid. " + + "Length range [2-256]"); + } + + //type + if(expenditure.getType() == null){ + errorMap.put(MasterDataConstants.EXPENDITURE_TYPE, "Expenditure type is missing in request data"); + } + //department id + if (StringUtils.isNotBlank(expenditure.getDepartmentId()) && StringUtils.isNotBlank(expenditure.getTenantId())) { + List departments = masterDepartmentUtil.fetchDepartment(Collections.singletonList(expenditure.getDepartmentId()), expenditure.getTenantId(), requestHeader); + if (departments == null || departments.isEmpty()) { + errorMap.put(MasterDataConstants.DEPARTMENT_ID, "Department id doesn't exist in the system"); + } + } + + if (!errorMap.isEmpty()) + throw new CustomException(errorMap); + } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java index 263df970..54790ec1 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java @@ -31,25 +31,20 @@ public void validateGovernmentRequestData(GovernmentRequest governmentRequest) { Government government = governmentRequest.getGovernment(); if (StringUtils.isEmpty(government.getId())) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government Id (Tenant id) is missing in request data"); + }else if (government.getId().length() < 1 || government.getId().length() > 64) { + throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id length is invalid."); } if (StringUtils.isEmpty(government.getName())) { throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name is missing in request data"); + }else if (government.getName().length() < 2 || government.getName().length() > 256) { + throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name length is invalid"); } Government existingGovernment = governmentRepository.findById(government.getId()); if (existingGovernment != null) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Duplicate government id"); } - - if (government.getId().length() < 1 || government.getId().length() > 64) { - throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id length is invalid."); - } - - if (government.getName().length() < 2 || government.getName().length() > 256) { - throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name length is invalid"); - } - }else { throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } @@ -61,11 +56,12 @@ public void validateGovernmentSearchRequestData(GovernmentSearchRequest governme GovernmentSearchCriteria criteria = governmentSearchRequest.getCriteria(); - if (criteria.getIds() == null || criteria.getIds().isEmpty()) { + if (criteria == null) { + throw new CustomException("INVALID_SEARCH_CRITERIA", "Search criteria is missing"); + }else if (criteria.getIds() == null || criteria.getIds().isEmpty()) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id list are missing"); } - } else { throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java index b86e9c9b..6bf2632e 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java @@ -46,6 +46,9 @@ public void validateProjectSearchRequest(ProjectSearchRequest projectSearchReque ProjectSearchCriteria projectSearchCriteria = projectSearchRequest.getCriteria(); + if (projectSearchCriteria == null) { + throw new CustomException("INVALID_SEARCH_CRITERIA", "Search criteria is missing"); + } if (StringUtils.isEmpty(projectSearchCriteria.getTenantId())) { throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java index a217d682..15234d81 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java @@ -18,6 +18,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; import java.io.IOException; +import java.util.Collections; import java.util.List; @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") @@ -42,10 +43,22 @@ public DepartmentApiController(ObjectMapper objectMapper, HttpServletRequest req this.request = request; } + /** + * @param body + * @return + */ @RequestMapping(value = "/_create", method = RequestMethod.POST) - public ResponseEntity departmentV1CreatePost(@ApiParam(value = "Details for the new department + RequestHeader (meta data of the API).", required = true) @Valid @RequestBody DepartmentRequest body) { + public ResponseEntity departmentV1CreatePost(@ApiParam(value = "Details for the new department" + + " RequestHeader (meta data of the API).", required = true) @Valid @RequestBody DepartmentRequest body) { - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + DepartmentRequest departmentRequest = departmentService.createDepartment(body); + + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + + DepartmentResponse departmentResponse = DepartmentResponse.builder().responseHeader(responseHeader) + .department(Collections.singletonList(departmentRequest.getDepartment())).build(); + + return new ResponseEntity(departmentResponse, HttpStatus.ACCEPTED); } @RequestMapping(value = "/_search", method = RequestMethod.POST) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java index 97c430fe..33557322 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ExpenditureApiController.java @@ -6,7 +6,10 @@ import org.egov.common.contract.response.ResponseHeader; import org.egov.service.ExpenditureService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.Expenditure; +import org.egov.web.models.ExpenditureRequest; +import org.egov.web.models.ExpenditureResponse; +import org.egov.web.models.ExpenditureSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -17,6 +20,7 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; +import java.util.Collections; import java.util.List; @javax.annotation.Generated(value = "org.egov.codegen.SpringBootCodegen", date = "2021-08-02T16:24:12.742+05:30") @@ -30,7 +34,7 @@ public class ExpenditureApiController { private final HttpServletRequest request; @Autowired - ExpenditureService expenditureService; + private ExpenditureService expenditureService; @Autowired private ResponseHeaderCreator responseHeaderCreator; @@ -44,8 +48,11 @@ public ExpenditureApiController(ObjectMapper objectMapper, HttpServletRequest re @RequestMapping(value = "/_create", method = RequestMethod.POST) public ResponseEntity eatV1CreatePost(@ApiParam(value = "Details for the new expenditure RequestHeader" + " (meta data of the API).", required = true) @Valid @RequestBody ExpenditureRequest body) { - - return new ResponseEntity(HttpStatus.NOT_IMPLEMENTED); + ExpenditureRequest expenditureRequest = expenditureService.createV1Expenditure(body); + ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); + ExpenditureResponse expenditureResponse = ExpenditureResponse.builder().responseHeader(responseHeader) + .expenditure(Collections.singletonList(expenditureRequest.getExpenditure())).build(); + return new ResponseEntity(expenditureResponse, HttpStatus.OK); } /** diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java index a44d4574..efce9c8c 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Expenditure.java @@ -36,8 +36,8 @@ public class Expenditure { private String name = null; @JsonProperty("type") private TypeEnum type = null; - @JsonProperty("parent") - private String parent = null; + @JsonProperty("departmentId") + private String departmentId = null; @JsonProperty("auditDetails") private AuditDetails auditDetails = null; diff --git a/domain-services/ifix-master-data-service/src/main/resources/application.properties b/domain-services/ifix-master-data-service/src/main/resources/application.properties index bb83f67c..34bdbede 100644 --- a/domain-services/ifix-master-data-service/src/main/resources/application.properties +++ b/domain-services/ifix-master-data-service/src/main/resources/application.properties @@ -20,3 +20,7 @@ ifix.master.expenditure.search.path=/expenditure/v1/_search ifix.department.entity.host=http://localhost:8032 ifix.department.entity.context.path=/ifix-department-entity ifix.department.entity.search.path=/departmentEntity/v1/_search + +ifix.master.department.host=http://localhost:8030 +ifix.master.department.context.path=/ifix-master-data +ifix.master.department.search.path=/department/v1/_search From a041ac7c874d21e9677a2d54dc60011c7e2ca8fb Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 2 Sep 2021 15:32:31 +0530 Subject: [PATCH 26/67] Changed primary timestamp in druid config (#53) Co-authored-by: rushang7-eGov --- .../fiscal-event-post-processor/druid-ingestion-config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json index 66b0eebe..b18663e1 100644 --- a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json +++ b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json @@ -18,7 +18,7 @@ "dataSchema": { "dataSource": "fiscal-event", "timestampSpec": { - "column": "ingestionTime", + "column": "eventTime", "format": "millis" }, "dimensionsSpec": { @@ -34,7 +34,7 @@ "eventId", { "type": "long", - "name": "eventTime" + "name": "ingestionTime" }, "eventType", "referenceId", From be0ad8cef88ea061a37ec0bca60683a53547fbdf Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Fri, 3 Sep 2021 12:13:18 +0530 Subject: [PATCH 27/67] Ifix 379 (#54) --- .../egov/service/DepartmentEntityService.java | 1 + .../egov/util/DepartmentEntityConstant.java | 2 ++ .../validator/DepartmentEntityValidator.java | 28 +++++++++++++++++-- .../org/egov/web/models/DepartmentEntity.java | 7 +---- 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java index c11f43e2..f489a025 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java @@ -43,6 +43,7 @@ public DepartmentEntityRequest createDepartmentEntity(DepartmentEntityRequest de } public List findAllByCriteria(DepartmentEntitySearchRequest departmentEntitySearchRequest) { + departmentEntityValidator.validateSearchDepartmentEntity(departmentEntitySearchRequest); List departmentEntityList = entityRepository.searchEntity(departmentEntitySearchRequest); if(departmentEntitySearchRequest.getCriteria().isGetAncestry()) { List departmentEntityAncestryList = new ArrayList<>(); diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java index 015e1a78..134c37f8 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java @@ -9,6 +9,7 @@ private DepartmentEntityConstant(){} public static final String DEPARTMENT_ENTITY_CODE = "DEPARTMENT_ENTITY_CODE"; public static final String DEPARTMENT_ENTITY_NAME = "DEPARTMENT_ENTITY_NAME"; public static final String DEPARTMENT_HIERARCHY_ID = "DEPARTMENT_HIERARCHY_ID"; + public static final String DEPARTMENT_CHILDREN = "DEPARTMENT_CHILDREN"; public static final String REQUEST_PAYLOAD_MISSING = "REQUEST_PAYLOAD"; public static final String ERROR_REQUEST_HEADER = "REQUEST_HEADER"; public static final String INVALID_REQUEST = "INVALID_REQUEST"; @@ -17,6 +18,7 @@ private DepartmentEntityConstant(){} public static final String INVALID_TENANT_ID = "INVALID_TENANT_ID"; public static final String INVALID_DEPARTMENT_ID = "INVALID_DEPARTMENT_ID"; public static final String ERROR_SEARCH_CRITERIA = "SEARCH_CRITERIA"; + public static final String INVALID_HIERARCHY_LEVEL= "INVALID_HIERARCHY_LEVEL"; //Search key parameters public static final String IDS = "Ids"; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java index 635b24a8..c3dfdd4b 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -7,6 +7,8 @@ import org.egov.util.GovernmentUtil; import org.egov.web.models.DepartmentEntity; import org.egov.web.models.DepartmentEntityRequest; +import org.egov.web.models.DepartmentEntitySearchCriteria; +import org.egov.web.models.DepartmentEntitySearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -78,9 +80,8 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn } if (departmentEntity.getChildren() == null) { - errorMap.put(DepartmentEntityConstant.USER_INFO, "Department children information is missing"); + errorMap.put(DepartmentEntityConstant.DEPARTMENT_CHILDREN, "Department children information is missing"); } - if (!errorMap.isEmpty()) { throw new CustomException(errorMap); } @@ -89,4 +90,27 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn throw new CustomException(DepartmentEntityConstant.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } } + + public void validateSearchDepartmentEntity(DepartmentEntitySearchRequest departmentEntitySearchRequest) { + DepartmentEntitySearchCriteria searchCriteria = departmentEntitySearchRequest.getCriteria(); + RequestHeader requestHeader = departmentEntitySearchRequest.getRequestHeader(); + Map errorMap = new HashMap<>(); + //header + if (requestHeader == null) { + throw new CustomException(DepartmentEntityConstant.ERROR_REQUEST_HEADER, "Request header is missing"); + } + if (requestHeader.getUserInfo() == null || requestHeader.getUserInfo().getUuid() == null) { + errorMap.put(DepartmentEntityConstant.USER_INFO, "User info is missing"); + } + //criteria + if (searchCriteria == null) { + throw new CustomException(DepartmentEntityConstant.ERROR_SEARCH_CRITERIA, "Search criteria is missing"); + } + if (StringUtils.isEmpty(searchCriteria.getTenantId())) { + errorMap.put(DepartmentEntityConstant.TENANT_ID, "Tenant id is missing in request data"); + } + if (!errorMap.isEmpty()) { + throw new CustomException(errorMap); + } + } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java index 605936e0..56003207 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java @@ -26,12 +26,7 @@ public class DepartmentEntity extends DepartmentEntityAbstract { @JsonProperty("children") @Valid - private List children = new ArrayList<>(); - - public DepartmentEntity addChildrenItem(String childrenItem) { - this.children.add(childrenItem); - return this; - } + private List children = null; } From f7a75c1420d9d645d5464bf57c99ec54c5a706ec Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Fri, 3 Sep 2021 17:18:31 +0530 Subject: [PATCH 28/67] Ifix 387 (#55) * IFIX 387 : - Department entity master service * IFIX-387 : fiscal event service * IFIX-387: Master Data service reformat. * IFIX-387: FiscalEvent Post Processor reformat. * IFIX-387 : fiscal event service- renamed yaml file * IFIX-387 : fiscal event service- renamed yaml file * IFIX-387 : fiscal event service- renamed yaml file * IFIX 387 : - Department entity master service--yaml file renamed * IFIX-387: FiscalEvent Post Processor yaml file addition * IFIX-387: Yaml file correction Co-authored-by: pintu-eGov --- .../fiscal-event-post-processor-0.1.0.yaml | 762 ++++++++++++ .../fiscal-event-post-processor/pom.xml | 2 +- .../FiscalEventUnbundledFlattenConsumer.java | 2 +- ...scalEventDereferenceEnrichmentService.java | 4 - .../FiscalEventDereferenceService.java | 36 +- .../service/FiscalEventUnbundleService.java | 12 +- .../java/org/egov/util/DepartmentUtil.java | 11 +- .../java/org/egov/util/ExpenditureUtil.java | 9 +- .../main/java/org/egov/util/ProjectUtil.java | 7 +- .../java/org/egov/web/models/FiscalEvent.java | 2 - .../org/egov/web/models/FiscalEventDruid.java | 6 +- .../egov/web/models/FiscalEventMongoDB.java | 6 +- .../egov/web/models/FiscalEventRequest.java | 5 - .../java/org/egov/web/models/Project.java | 3 - .../fiscal-event-service-0.1.0.yaml | 374 ++++++ domain-services/fiscal-event-service/pom.xml | 2 +- .../main/java/org/egov/producer/Producer.java | 2 - .../repository/FiscalEventRepository.java | 3 +- .../org/egov/service/FiscalEventService.java | 4 +- .../src/main/java/org/egov/util/CoaUtil.java | 11 +- .../java/org/egov/util/FiscalEventUtil.java | 7 +- .../main/java/org/egov/util/ProjectUtil.java | 6 +- .../org/egov/util/ResponseHeaderCreator.java | 2 +- .../main/java/org/egov/util/TenantUtil.java | 13 +- .../egov/validator/FiscalEventValidator.java | 9 +- .../web/controllers/FiscalApiController.java | 2 +- .../java/org/egov/web/models/FiscalEvent.java | 1 - .../ifix-department-entity-service-0.1.0.yaml | 467 +++++++ .../ifix-department-entity-service/pom.xml | 2 +- .../DepartmentEntityRepository.java | 2 +- .../DepartmentEntityEnrichmentService.java | 4 +- .../egov/service/DepartmentEntityService.java | 8 +- ...rtmentHierarchyLevelEnrichmentService.java | 2 +- .../util/DepartmentEntityAncestryUtil.java | 1 - .../egov/util/DepartmentEntityConstant.java | 5 +- .../org/egov/util/DepartmentEntityUtil.java | 2 +- .../java/org/egov/util/DepartmentUtil.java | 4 +- .../java/org/egov/util/GovernmentUtil.java | 1 - .../org/egov/util/ResponseHeaderCreator.java | 2 +- .../validator/DepartmentEntityValidator.java | 14 +- .../DepartmentHierarchyLevelValidator.java | 2 +- .../DepartmentEntityApiController.java | 6 +- ...DepartmentHierarchyLevelApiController.java | 5 +- .../org/egov/web/models/DepartmentEntity.java | 3 - .../web/models/DepartmentEntityAbstract.java | 9 +- .../web/models/DepartmentEntityAncestry.java | 1 - .../web/models/DepartmentEntityResponse.java | 1 - .../web/models/DepartmentHierarchyLevel.java | 2 - ...epartmentHierarchyLevelSearchCriteria.java | 1 - .../ifix-master-data-service-0.1.0.yaml | 1083 +++++++++++++++++ .../ifix-master-data-service/pom.xml | 2 +- .../repository/ChartOfAccountRepository.java | 9 +- .../egov/repository/DepartmentRepository.java | 1 - .../egov/repository/GovernmentRepository.java | 3 +- .../repository/ServiceRequestRepository.java | 8 +- .../egov/service/COAEnrichmentService.java | 9 +- .../egov/service/ChartOfAccountService.java | 2 + .../service/DepartmentEnrichmentService.java | 12 +- .../service/GovernmentEnrichmentService.java | 8 +- .../org/egov/service/GovernmentService.java | 8 - .../ProjectDepartmentEntityIntegration.java | 4 +- .../service/ProjectEnrichmentService.java | 10 +- .../src/main/java/org/egov/util/CoaUtil.java | 19 +- .../java/org/egov/util/ExpenditureUtil.java | 1 - .../org/egov/util/MasterDataServiceUtil.java | 3 +- .../org/egov/util/ResponseHeaderCreator.java | 2 +- .../validator/ChartOfAccountValidator.java | 2 +- .../egov/validator/DepartmentValidator.java | 9 +- .../egov/validator/ExpenditureValidator.java | 10 +- .../egov/validator/GovernmentValidator.java | 8 +- .../org/egov/validator/ProjectValidator.java | 15 +- .../ChartOfAccountApiController.java | 4 +- .../controllers/DepartmentApiController.java | 8 +- .../controllers/GovernmentApiController.java | 7 +- .../web/controllers/ProjectApiController.java | 13 +- .../egov/web/models/COASearchCriteria.java | 2 +- .../models/DepartmentEntityAttributes.java | 1 - .../web/models/DepartmentSearchCriteria.java | 3 +- .../java/org/egov/web/models/Government.java | 3 - 79 files changed, 2883 insertions(+), 233 deletions(-) create mode 100644 domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml create mode 100644 domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml create mode 100644 domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml create mode 100644 domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml diff --git a/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml b/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml new file mode 100644 index 00000000..6d4ef9e2 --- /dev/null +++ b/domain-services/fiscal-event-post-processor/fiscal-event-post-processor-0.1.0.yaml @@ -0,0 +1,762 @@ +--- +openapi: 3.0.0 +info: + title: fiscal-event-post-processor + version: 0.1.0 +servers: +- url: + description: SwaggerHub API Auto Mocking +paths: {} +components: + schemas: + Government: + type: object + properties: + id: + type: string + example: pb + name: + type: string + example: Punjab + Department: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: 5d664a9f-9367-458a-aa5f-07fb18b90adc + code: + type: string + description: Unique department code + example: DWSS + name: + type: string + description: Name of the department + example: Department of Water Supply & Sanitation + description: Department details + Expenditure: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: d334d99a-b5c1-426c-942b-f11b5b5454fe + code: + type: string + description: Unique Expenditure code + example: JJM + name: + type: string + description: Name of the Expenditure + example: Jal Jeevan Mission + type: + type: string + description: Type of the Expenditure + enum: + - Scheme + - Non-Scheme + description: Expenditure details + DepartmentEntityAttributes: + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + description: The list basic attributes of a department entity that are stored as part of the ancestry list + DepartmentEntity: + required: + - code + - hierarchyLevelId + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + ancestry: + type: array + items: + $ref: '#/components/schemas/DepartmentEntityAttributes' + description: This object captures the information for department entity + readOnly: true + Project: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: 6ab1b1d2-e224-46fa-b53b-ac83b3c7ce95 + code: + type: string + description: Unique Project code + example: PWT + name: + type: string + description: Name of the Project + example: Peepli Water Tank + description: Captures the Project attributes + ChartOfAccount: + type: object + properties: + id: + type: string + description: Unique system generated UUID + example: e9f940d4-69aa-4bbb-aa82-111b8948a6b6 + coaCode: + type: string + description: Chart of account concatinated string + example: 1234-123-123-12-12-12 + majorHead: + type: string + description: Major head code + example: "1234" + majorHeadName: + type: string + description: Major head name + majorHeadType: + type: string + description: Major head code type + example: Revenue + subMajorHead: + type: string + description: Sub-Major head code + example: "123" + subMajorHeadName: + type: string + description: Sub-Major head name + minorHead: + type: string + description: Minor head code + example: "123" + minorHeadName: + type: string + description: Minor head name + subHead: + type: string + description: Sub-Head code + example: "12" + subHeadName: + type: string + description: Sub-Head name + groupHead: + type: string + description: Group head code + example: "12" + groupHeadName: + type: string + description: Group head name + objectHead: + type: string + description: Object head code + example: "12" + objectHeadName: + type: string + description: Object head name + Amount: + required: + - amount + - coa + type: object + properties: + id: + type: string + description: System generated UUID + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coaId: + type: string + description: Id of Chart of Account from the iFix master data. + example: d1e87330-4de0-4d15-8d92-d40bfa9b3ca4 + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + FiscalEvent: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID. + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + projectId: + type: string + description: The unique reference id of the project under which the event is occurring + format: uuid + example: 090d1d25-8b88-46a3-b4c9-95b66483beb5 + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/Amount' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + FiscalEventRequest: + required: + - fiscalEvent + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + fiscalEvent: + $ref: '#/components/schemas/FiscalEvent' + description: Fiscal event request along with request metadata + AmountDetailsDeReferenced: + required: + - amount + - coa + type: object + properties: + id: + type: string + description: System generated UUID + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa: + $ref: '#/components/schemas/ChartOfAccount' + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + FiscalEventDeReferenced: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID. + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government: + $ref: '#/components/schemas/Government' + department: + $ref: '#/components/schemas/Department' + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + expenditure: + $ref: '#/components/schemas/Expenditure' + project: + $ref: '#/components/schemas/Project' + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/AmountDetailsDeReferenced' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: It gets the whole master data objects based on the reference ids present in the incoming request + FiscalEventMongoDB: + $ref: '#/components/schemas/FiscalEventDeReferenced' + FiscalEventLineItemUnbundled: + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID of Line Item + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + eventId: + type: string + description: Fiscal Event Reference Id + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government: + $ref: '#/components/schemas/Government' + department: + $ref: '#/components/schemas/Department' + Expenditure: + $ref: '#/components/schemas/Expenditure' + project: + $ref: '#/components/schemas/Project' + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa: + $ref: '#/components/schemas/ChartOfAccount' + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: This is the unbundled line item into individual record from a given fiscal event. + FiscalEventLineItemFlattened: + type: object + properties: + version: + type: string + description: Version of the Data Model Definition + example: 1.0.0 + id: + type: string + description: System generated UUID of Line Item + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + eventId: + type: string + description: Fiscal Event Reference Id + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + type: string + description: Tenant Id + nullable: false + example: pb + government.id: + type: string + example: pb + government.name: + type: string + example: Punjab + department.id: + type: string + description: Unique system generated UUID + example: 5d664a9f-9367-458a-aa5f-07fb18b90adc + department.code: + type: string + description: Unique department code + example: DWSS + department.name: + type: string + description: Name of the department + example: Department of Water Supply & Sanitation + departmentEntity.id: + type: string + description: Unique system generated UUID + example: 054c8070-3135-47ce-a6ca-f425d2b57b02 + departmentEntity.code: + type: string + description: Unique department entity code + example: APS + departmentEntity.name: + type: string + description: Name of the department entity + example: Anandpur Sahib + departmentEntity.hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 3 + departmentEntity.ancestry[0].id: + type: string + description: Unique system generated UUID + example: 99e988ee-3036-47e3-b907-d3273c18161f + departmentEntity.ancestry[0].code: + type: string + description: Unique department entity code + example: DWSS + departmentEntity.ancestry[0].name: + type: string + description: Name of the department entity + example: Department of Water Supply & Sanitation + departmentEntity.ancestry[0].hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 0 + departmentEntity.ancestry[1].id: + type: string + description: Unique system generated UUID + example: 9d59e2bf-2892-4a27-977a-f3cfd7d2e024 + departmentEntity.ancestry[1].code: + type: string + description: Unique department entity code + example: South + departmentEntity.ancestry[1].name: + type: string + description: Name of the department entity + example: South Zone + departmentEntity.ancestry[1].hierarchyLevel: + type: number + description: Hierarchy level of the department entity + example: 1 + expenditure.id: + type: string + description: Unique system generated UUID + example: d334d99a-b5c1-426c-942b-f11b5b5454fe + expenditure.code: + type: string + description: Unique Expenditure code + example: JJM + expenditure.name: + type: string + description: Name of the Expenditure + example: Jal Jeevan Mission + expenditure.type: + type: string + description: Type of the Expenditure + enum: + - Scheme + - Non-Scheme + project.id: + type: string + description: Unique system generated UUID + example: 6ab1b1d2-e224-46fa-b53b-ac83b3c7ce95 + project.code: + type: string + description: Unique Project code + example: PWT + project.name: + type: string + description: Name of the Project + example: Peepli Water Tank + eventType: + type: string + description: Captures the event type (eg- Sanction(B), Appropriation(B), Allocation(Fin-AD-BCO-DDO)(B), IntraTransfer (C), Inter Transfer (C), Demand(A), Receipt (C), Bill(A),Payment (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coa.id: + type: string + description: Unique system generated UUID + example: e9f940d4-69aa-4bbb-aa82-111b8948a6b6 + coa.coaCode: + type: string + description: Chart of account concatinated string + example: 1234-123-123-12-12-12 + coa.majorHead: + type: string + description: Major head code + example: "1234" + coa.majorHeadName: + type: string + description: Major head name + coa.majorHeadType: + type: string + description: Major head code type + example: Revenue + coa.subMajorHead: + type: string + description: Sub-Major head code + example: "123" + coa.subMajorHeadName: + type: string + description: Sub-Major head name + coa.minorHead: + type: string + description: Minor head code + example: "123" + coa.minorHeadName: + type: string + description: Minor head name + coa.subHead: + type: string + description: Sub-Head code + example: "12" + coa.subHeadName: + type: string + description: Sub-Head name + coa.groupHead: + type: string + description: Group head code + example: "12" + coa.groupHeadName: + type: string + description: Group head name + coa.objectHead: + type: string + description: Object head code + example: "12" + coa.objectHeadName: + type: string + description: Object head name + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: This is the flattened structure of line item that will get persisted to Druid + FiscalEventDruid: + $ref: '#/components/schemas/FiscalEventLineItemFlattened' + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/fiscal-event-post-processor/pom.xml b/domain-services/fiscal-event-post-processor/pom.xml index c170e0b0..576ee819 100644 --- a/domain-services/fiscal-event-post-processor/pom.xml +++ b/domain-services/fiscal-event-post-processor/pom.xml @@ -5,7 +5,7 @@ fiscal-event-post-processor jar fiscal-event-post-processor - 1.0.0 + 0.1.0 1.8 ${java.version} diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java index 36b2fc41..2fd8f2fa 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java @@ -43,7 +43,7 @@ public void listen(final HashMap record, @Header(KafkaHeaders.RE mapper.enable(DeserializationFeature.ACCEPT_EMPTY_STRING_AS_NULL_OBJECT); try { FiscalEventDeReferenced fiscalEventDeReferenced = mapper.convertValue(record, FiscalEventDeReferenced.class); - List fiscalEventLineItemUnbundledList = unbundleService.unbundle(fiscalEventDeReferenced); + List fiscalEventLineItemUnbundledList = unbundleService.unbundle(fiscalEventDeReferenced); List flattenJsonDataList = flattenService.getFlattenData(fiscalEventLineItemUnbundledList); diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java index 3012af60..1991e508 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceEnrichmentService.java @@ -2,17 +2,13 @@ import lombok.extern.slf4j.Slf4j; -import org.egov.common.contract.AuditDetails; import org.egov.common.contract.request.RequestHeader; import org.egov.util.MasterDataConstants; import org.egov.web.models.FiscalEvent; import org.egov.web.models.FiscalEventDeReferenced; import org.egov.web.models.FiscalEventRequest; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.UUID; - @Service @Slf4j public class FiscalEventDereferenceEnrichmentService { diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java index 34e659af..05ebe830 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java @@ -11,9 +11,7 @@ import org.springframework.stereotype.Service; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map; @Service @Slf4j @@ -38,17 +36,17 @@ public class FiscalEventDereferenceService { private DepartmentUtil departmentUtil; public FiscalEventDeReferenced dereference(FiscalEventRequest fiscalEventRequest) { - FiscalEventDeReferenced fiscalEventDeReferenced = new FiscalEventDeReferenced(); - dereferenceTenantId(fiscalEventRequest,fiscalEventDeReferenced); - dereferenceCoaId(fiscalEventRequest,fiscalEventDeReferenced); + FiscalEventDeReferenced fiscalEventDeReferenced = new FiscalEventDeReferenced(); + dereferenceTenantId(fiscalEventRequest, fiscalEventDeReferenced); + dereferenceCoaId(fiscalEventRequest, fiscalEventDeReferenced); dereferenceProjectId(fiscalEventRequest, fiscalEventDeReferenced); - enricher.enrich(fiscalEventRequest,fiscalEventDeReferenced); + enricher.enrich(fiscalEventRequest, fiscalEventDeReferenced); return fiscalEventDeReferenced; } private void dereferenceTenantId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { List governments = governmentUtil.getGovernmentFromGovernmentService(fiscalEventRequest); - if(!governments.isEmpty()){ + if (!governments.isEmpty()) { fiscalEventDeReferenced.setGovernment(governments.get(0)); } fiscalEventDeReferenced.setTenantId(fiscalEventRequest.getFiscalEvent().getTenantId()); @@ -57,16 +55,16 @@ private void dereferenceTenantId(FiscalEventRequest fiscalEventRequest, FiscalEv private void dereferenceCoaId(FiscalEventRequest fiscalEventRequest, FiscalEventDeReferenced fiscalEventDeReferenced) { //copy the amount details except chart of account in deReferenced amount List amtDetailsDereferenced = new ArrayList<>(); - if(fiscalEventRequest.getFiscalEvent() != null - && fiscalEventRequest.getFiscalEvent().getAmountDetails()!=null - && !fiscalEventRequest.getFiscalEvent().getAmountDetails().isEmpty()){ - for(Amount amount : fiscalEventRequest.getFiscalEvent().getAmountDetails()){ - AmountDetailsDeReferenced amountDetailsDeReferenced = new AmountDetailsDeReferenced(); + if (fiscalEventRequest.getFiscalEvent() != null + && fiscalEventRequest.getFiscalEvent().getAmountDetails() != null + && !fiscalEventRequest.getFiscalEvent().getAmountDetails().isEmpty()) { + for (Amount amount : fiscalEventRequest.getFiscalEvent().getAmountDetails()) { + AmountDetailsDeReferenced amountDetailsDeReferenced = new AmountDetailsDeReferenced(); amountDetailsDeReferenced.setAmount(amount.getAmount()); amountDetailsDeReferenced.setFromBillingPeriod(amount.getFromBillingPeriod()); amountDetailsDeReferenced.setToBillingPeriod(amount.getToBillingPeriod()); amountDetailsDeReferenced.setId(amount.getId()); - ChartOfAccount coa = new ChartOfAccount(); + ChartOfAccount coa = new ChartOfAccount(); coa.setId(amount.getCoaId()); //coaIds.add(amount.getCoaId()); amountDetailsDeReferenced.setCoa(coa); @@ -80,13 +78,13 @@ private void dereferenceCoaId(FiscalEventRequest fiscalEventRequest, FiscalEvent fiscalEventRequest.getFiscalEvent()); //copy the amount details except chart of account in deReferenced amount List updatedAmtDereferences = new ArrayList<>(); - if(!chartOfAccounts.isEmpty()){ - for(AmountDetailsDeReferenced amtDeReferenced : amtDetailsDereferenced){ + if (!chartOfAccounts.isEmpty()) { + for (AmountDetailsDeReferenced amtDeReferenced : amtDetailsDereferenced) { AmountDetailsDeReferenced newAmtDereference = new AmountDetailsDeReferenced(); - BeanUtils.copyProperties(amtDeReferenced,newAmtDereference); + BeanUtils.copyProperties(amtDeReferenced, newAmtDereference); - for(ChartOfAccount chartOfAccount : chartOfAccounts){ - if(chartOfAccount.getId().equals(amtDeReferenced.getCoa().getId())){ + for (ChartOfAccount chartOfAccount : chartOfAccounts) { + if (chartOfAccount.getId().equals(amtDeReferenced.getCoa().getId())) { newAmtDereference.setCoa(chartOfAccount); break; } @@ -113,7 +111,7 @@ private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalE String expenditureId = null; String departmentId = null; - if(projectNode != null && !projectNode.isEmpty()) { + if (projectNode != null && !projectNode.isEmpty()) { expenditureId = projectNode.get("expenditureId").asText(); departmentId = projectNode.get("departmentEntity").get("departmentId").asText(); diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java index 0daef5d2..4bc3c1da 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventUnbundleService.java @@ -16,16 +16,17 @@ public class FiscalEventUnbundleService { /** * Unbundled the dereference fiscal event + * * @param fiscalEventDeReferenced * @return */ public List unbundle(FiscalEventDeReferenced fiscalEventDeReferenced) { - List fiscalEventLineItemUnbundledList = new ArrayList<>(); + List fiscalEventLineItemUnbundledList = new ArrayList<>(); List amountDetails = fiscalEventDeReferenced.getAmountDetails(); - if(amountDetails != null && !amountDetails.isEmpty()){ - for(AmountDetailsDeReferenced amountDetailsDeReferenced : amountDetails){ + if (amountDetails != null && !amountDetails.isEmpty()) { + for (AmountDetailsDeReferenced amountDetailsDeReferenced : amountDetails) { fiscalEventLineItemUnbundledList.add(getUnbundleFiscalEventFromDereferenceEvent( - amountDetailsDeReferenced,fiscalEventDeReferenced)); + amountDetailsDeReferenced, fiscalEventDeReferenced)); } } @@ -33,14 +34,13 @@ public List unbundle(FiscalEventDeReferenced fisca } /** - * * @param amountDetailsDeReferenced * @param fiscalEventDeReferenced * @return */ private FiscalEventLineItemUnbundled getUnbundleFiscalEventFromDereferenceEvent(AmountDetailsDeReferenced amountDetailsDeReferenced, FiscalEventDeReferenced fiscalEventDeReferenced) { - FiscalEventLineItemUnbundled fiscalEventLineItemUnbundled = new FiscalEventLineItemUnbundled(); + FiscalEventLineItemUnbundled fiscalEventLineItemUnbundled = new FiscalEventLineItemUnbundled(); fiscalEventLineItemUnbundled.setId(amountDetailsDeReferenced.getId()); fiscalEventLineItemUnbundled.setEventId(fiscalEventDeReferenced.getId()); diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java index f700a5f8..86bd78a9 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/DepartmentUtil.java @@ -43,12 +43,13 @@ public List getDepartmentReference(String tenantId, String departmen Object response = serviceRequestRepository.fetchResult(createSearchDepartmentUrl(), departmentMap); - try{ - List departmentList = JsonPath.read(response, MasterDataConstants.DEPARTMENT_JSON_PATH); + try { + List departmentList = JsonPath.read(response, MasterDataConstants.DEPARTMENT_JSON_PATH); - return objectMapper.convertValue(departmentList, new TypeReference>() {}); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + return objectMapper.convertValue(departmentList, new TypeReference>() { + }); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse project response for projectId"); } } return Collections.emptyList(); diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java index 0774489c..ef7e3a50 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ExpenditureUtil.java @@ -48,12 +48,13 @@ public List getExpenditureReference(String tenantId, String expendi Object response = serviceRequestRepository.fetchResult(createSearchExpenditureUrl(), expenditureMap); - try{ + try { List expenditureList = JsonPath.read(response, MasterDataConstants.EXPENDITURE_JSON_PATH); - return objectMapper.convertValue(expenditureList, new TypeReference>() {}); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + return objectMapper.convertValue(expenditureList, new TypeReference>() { + }); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse project response for projectId"); } } return Collections.emptyList(); diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java index 078c8f82..f2d2b4a3 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/util/ProjectUtil.java @@ -1,10 +1,8 @@ package org.egov.util; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; -import com.jayway.jsonpath.JsonPath; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.config.FiscalEventPostProcessorConfig; @@ -12,13 +10,11 @@ import org.egov.tracer.model.CustomException; import org.egov.web.models.DepartmentEntity; import org.egov.web.models.FiscalEventRequest; -import org.egov.web.models.Project; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; @Component @@ -33,9 +29,9 @@ public class ProjectUtil { @Autowired ObjectMapper objectMapper; + /** * @param fiscalEventRequest - * @param idMap * @return */ public JsonNode getProjectReference(FiscalEventRequest fiscalEventRequest) { @@ -69,7 +65,6 @@ private String createSearchProjectUrl() { } /** - * * @param departmentEntityNode * @return */ diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java index ba18053e..73c17d05 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEvent.java @@ -1,7 +1,6 @@ package org.egov.web.models; import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonFormat; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonValue; import io.swagger.annotations.ApiModel; @@ -12,7 +11,6 @@ import javax.validation.Valid; import java.util.ArrayList; import java.util.List; -import java.util.UUID; /** * This object captures the fiscal information of external systems. diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java index aa1f5e31..a6321413 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventDruid.java @@ -1,6 +1,9 @@ package org.egov.web.models; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; import org.springframework.validation.annotation.Validated; /** @@ -12,7 +15,6 @@ @Getter @Setter @AllArgsConstructor -//@NoArgsConstructor @Builder public class FiscalEventDruid { diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java index 8b527c89..4c0530af 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventMongoDB.java @@ -1,6 +1,9 @@ package org.egov.web.models; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Getter; +import lombok.Setter; import org.springframework.validation.annotation.Validated; /** @@ -12,7 +15,6 @@ @Getter @Setter @AllArgsConstructor -//@NoArgsConstructor @Builder public class FiscalEventMongoDB { diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java index 4e32a430..846125f2 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/FiscalEventRequest.java @@ -6,11 +6,6 @@ import org.egov.common.contract.request.RequestHeader; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.ArrayList; -import java.util.List; -import java.util.UUID; - /** * This object captures the fiscal information of external systems. */ diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java index 8caecdde..80ca0c18 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/web/models/Project.java @@ -26,9 +26,6 @@ public class Project { @JsonProperty("name") private String name = null; -// -// @JsonProperty("departmentEntity") -// private DepartmentEntity departmentEntity = null; } diff --git a/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml b/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml new file mode 100644 index 00000000..46bb760c --- /dev/null +++ b/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml @@ -0,0 +1,374 @@ +--- +openapi: 3.0.0 +info: + title: fiscal-event-service + version: 0.1.0 +servers: +- url: https:///fiscal-event-service + description: SwaggerHub API Auto Mocking +paths: + /fiscal/events/v1/_push: + post: + tags: + - Fiscal Events + summary: Create(publish) new fiscal event on iFix + description: Create the new fiscal event + requestBody: + description: Details for the new fiscal event + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/FiscalEventRequest' + required: true + responses: + "202": + description: Event published successfully + content: + '*/*': + schema: + $ref: '#/components/schemas/FiscalEventResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /fiscal/events/v1/_search: + post: + tags: + - Fiscal Events + summary: Get the list fiscal events. + description: | + Based on the criteria get the list of events. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/FiscalEventGetRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/FiscalEventResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + FiscalEvent: + required: + - amountDetails + - eventType + - referenceId + - tenantId + - transactionTime + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: System generated UUID. + readOnly: true + example: fecbbf1d-d6e3-4f24-9935-02c33b9248e0 + tenantId: + maxLength: 256 + minLength: 2 + type: string + description: Tenant Id + nullable: false + example: pb + projectId: + type: string + description: The unique reference id of the project under which the event is occurring + format: uuid + example: 090d1d25-8b88-46a3-b4c9-95b66483beb5 + eventType: + maxLength: 64 + minLength: 1 + type: string + description: Captures the event type (eg- SANCTION(B), APPROPRIATION(B), ALLOCATION(FIN-AD-BCO-DDO)(B), INTRA_TRANSFER (C), INTER_TRANSFER (C), DEMAND(A), RECEIPT (C), BILL(A),PAYMENT (C) + nullable: false + example: Appropriation + eventTime: + type: integer + description: when the event occured at source system level + format: int64 + example: 1628177497000 + ingestionTime: + type: integer + description: when the event arrived in ifix + format: int64 + nullable: false + readOnly: true + example: 1628177497000 + referenceId: + maxLength: 64 + minLength: 1 + type: string + description: reference unique id(transaction id) of the caller system + example: 013e9c56-8207-4dac-9f4d-f1e20bd824e7 + parentEventId: + maxLength: 64 + minLength: 1 + type: string + description: If this is a follow up event then it will refer to the parent event using this reference id. + nullable: true + example: 7d476bb0-bc9f-48e2-8ad4-5a4a36220779 + parentReferenceId: + maxLength: 64 + minLength: 1 + type: string + description: If this is a follow up event then it will refer to the parent event in source system using this reference id. + nullable: true + example: 77f23efe-879d-407b-8f23-7b8dd5b2ecb1 + amountDetails: + type: array + items: + $ref: '#/components/schemas/Amount' + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + Amount: + required: + - amount + - coa + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: System generated UUID + readOnly: true + example: 51c9c03c-1607-4dd5-9e0e-93bbf860f6f7 + amount: + type: number + description: Transaction Amount + example: 10234.5 + coaId: + maxLength: 64 + minLength: 1 + type: string + description: Id of Chart of Account from the iFix master data. + example: d1e87330-4de0-4d15-8d92-d40bfa9b3ca4 + fromBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1622907239000 + toBillingPeriod: + type: integer + description: Start date of the billing period for which transaction is applicable + format: int64 + example: 1628177643000 + description: Capture the transaction amount and chart of account corresponding to the transaction amount + Criteria: + required: + - eventType + - tenantId + type: object + properties: + ids: + type: array + description: List of event ids + items: + maxItems: 100 + type: string + tenantId: + maxLength: 256 + minLength: 2 + type: string + description: Tenant Id + nullable: false + eventType: + maxLength: 64 + minLength: 1 + type: string + description: Captures the event type(eg- bill, receipt, expenditure) + nullable: false + fromEventTime: + type: integer + description: Search events b/w transaction time(Start date) + format: int64 + toEventTime: + type: integer + description: Search events b/w transaction time(End date) + format: int64 + referenceId: + type: array + items: + maxItems: 100 + type: string + description: The object contains all the search criteria of the fiscal events + FiscalEventRequest: + required: + - fiscalInfo + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + fiscalEvent: + $ref: '#/components/schemas/FiscalEvent' + description: Fiscal event request along with request metadata + FiscalEventGetRequest: + required: + - fiscalInfo + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/Criteria' + description: Fiscal event request along with request metadata + FiscalEventResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + fiscalEvent: + type: array + items: + $ref: '#/components/schemas/FiscalEvent' + description: Contains the ResponseHeader and the enriched fiscal information + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/fiscal-event-service/pom.xml b/domain-services/fiscal-event-service/pom.xml index 749fe9fd..d6cb430e 100644 --- a/domain-services/fiscal-event-service/pom.xml +++ b/domain-services/fiscal-event-service/pom.xml @@ -5,7 +5,7 @@ fiscal-event-service jar fiscal-event-service - 1.0.0 + 0.1.0 1.8 ${java.version} diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java b/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java index f00e15b4..3b0d2169 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/producer/Producer.java @@ -1,9 +1,7 @@ package org.egov.producer; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.StringUtils; import org.egov.tracer.kafka.CustomKafkaTemplate; -import org.egov.tracer.model.CustomException; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java index c345bf6f..063b15e2 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java @@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j; import org.egov.repository.querybuilder.FiscalEventQueryBuilder; import org.egov.web.models.Criteria; -import org.egov.web.models.FiscalEvent; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Query; @@ -24,6 +23,6 @@ public class FiscalEventRepository { public List searchFiscalEvent(Criteria searchCriteria) { Query searchQuery = eventQueryBuilder.buildSearchQuery(searchCriteria); - return (mongoTemplate.find(searchQuery, Object.class,"fiscalEvent")); + return (mongoTemplate.find(searchQuery, Object.class, "fiscalEvent")); } } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java index 1d83752a..f9b9b9da 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/service/FiscalEventService.java @@ -1,7 +1,6 @@ package org.egov.service; -import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.config.FiscalEventConfiguration; @@ -44,13 +43,14 @@ public class FiscalEventService { /** * Validate , enrich and push the fiscal Event request to topic + * * @param fiscalEventRequest * @return */ public FiscalEventRequest fiscalEventsV1PushPost(FiscalEventRequest fiscalEventRequest) { validator.validateFiscalEventPushPost(fiscalEventRequest); enricher.enrichFiscalEventPushPost(fiscalEventRequest); - producer.push(eventConfiguration.getFiscalPushRequest(),fiscalEventRequest); + producer.push(eventConfiguration.getFiscalPushRequest(), fiscalEventRequest); return fiscalEventRequest; } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java index 13e69b8c..93bcf0a4 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/CoaUtil.java @@ -31,6 +31,7 @@ public class CoaUtil { /** * Get the COA Details from master data service + * * @param requestHeader * @param fiscalEvent * @return @@ -39,12 +40,12 @@ public List getCOAIdsFromCOAService(RequestHeader requestHeader, FiscalE String url = createCoaSearchUrl(); Map coaSearchRequest = createSearchCoaRequest(requestHeader, fiscalEvent); - Object response = serviceRequestRepository.fetchResult(url,coaSearchRequest); + Object response = serviceRequestRepository.fetchResult(url, coaSearchRequest); List responseCoaIds = null; - try{ + try { responseCoaIds = JsonPath.read(response, MasterDataConstants.COA_IDS_JSON_PATH); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse coa response for coaIds"); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse coa response for coaIds"); } return responseCoaIds; } @@ -69,7 +70,7 @@ private Map createSearchCoaRequest(RequestHeader requestHeader, } private String createCoaSearchUrl() { - StringBuilder uriBuilder = new StringBuilder(configuration.getIfixMasterCoaHost()) + StringBuilder uriBuilder = new StringBuilder(configuration.getIfixMasterCoaHost()) .append(configuration.getIfixMasterCoaContextPath()).append(configuration.getIfixMasterCoaSearchPath()); return uriBuilder.toString(); } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java index cbf5a8f0..abca6450 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/FiscalEventUtil.java @@ -3,13 +3,8 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.AuditDetails; -import org.egov.common.contract.request.RequestHeader; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.LinkedHashMap; -import java.util.List; - @Component @Slf4j public class FiscalEventUtil { @@ -23,7 +18,7 @@ public class FiscalEventUtil { */ public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); - if(isCreate) + if (isCreate) return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); else return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java index 5ebdace1..9119b3e1 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java @@ -43,12 +43,12 @@ public boolean validateProjectId(FiscalEventRequest fiscalEventRequest) { Object response = serviceRequestRepository.fetchResult(createSearchProjectUrl(), ProjectMap); - try{ + try { List list = JsonPath.read(response, MasterDataConstants.PROJECT_LIST); return list != null && !list.isEmpty(); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse project response for projectId"); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse project response for projectId"); } } return false; diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java index c802136b..e1a495c7 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -16,7 +16,7 @@ public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader Long ts = null; if (requestInfo != null) ts = requestInfo.getTs(); - final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String sign = requestInfo.getSignature() != null ? requestInfo.getSignature() : ""; final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; final String responseStatus = success ? "successful" : "failed"; diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java index 910d45ba..5c533567 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/TenantUtil.java @@ -7,11 +7,13 @@ import org.egov.config.FiscalEventConfiguration; import org.egov.repository.ServiceRequestRepository; import org.egov.tracer.model.CustomException; -import org.egov.web.models.FiscalEventRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @Component @Slf4j @@ -24,7 +26,6 @@ public class TenantUtil { ServiceRequestRepository serviceRequestRepository; /** - * * @param tenantId * @param requestHeader * @return @@ -42,12 +43,12 @@ public boolean validateTenant(String tenantId, RequestHeader requestHeader) { Object response = serviceRequestRepository.fetchResult(createSearchTenantUrl(), tenantMap); - try{ + try { List list = JsonPath.read(response, MasterDataConstants.TENANT_LIST); return list != null && !list.isEmpty(); - }catch (Exception e){ - throw new CustomException(MasterDataConstants.JSONPATH_ERROR,"Failed to parse government response for tenantId"); + } catch (Exception e) { + throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse government response for tenantId"); } } return false; diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index 0977d6fc..d3c05008 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -41,7 +41,7 @@ public class FiscalEventValidator { */ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null - && fiscalEventRequest.getFiscalEvent() != null) { + && fiscalEventRequest.getFiscalEvent() != null) { Map errorMap = new HashMap<>(); if (StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getReferenceId())) { @@ -59,7 +59,7 @@ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { validateTenantId(fiscalEventRequest, errorMap); validateProjectId(fiscalEventRequest, errorMap); validateFiscalEventAmountDetails(fiscalEventRequest, errorMap); - validateParentEventId(fiscalEventRequest,errorMap); + validateParentEventId(fiscalEventRequest, errorMap); if (!errorMap.isEmpty()) { throw new CustomException(errorMap); @@ -100,7 +100,6 @@ private void validateReqHeader(RequestHeader requestHeader) { } - /** * Validate the fiscal event request - amount details(line items) attributes * @@ -142,8 +141,8 @@ private void validateFiscalEventAmountDetails(FiscalEventRequest fiscalEventRequ * @param fiscalEventRequest */ public void validateTenantId(FiscalEventRequest fiscalEventRequest, Map errorMap) { - if(StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getTenantId())){ - errorMap.put(MasterDataConstants.TENANT_ID,"Tenant id is missing in request"); + if (StringUtils.isBlank(fiscalEventRequest.getFiscalEvent().getTenantId())) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is missing in request"); } boolean isValidTenant = false; if (fiscalEventRequest.getFiscalEvent() != null && StringUtils.isNotBlank(fiscalEventRequest.getFiscalEvent().getTenantId())) { diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java index 5ded5baa..173496cc 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/controllers/FiscalApiController.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; import org.egov.common.contract.response.ResponseHeader; +import org.egov.service.FiscalEventService; import org.egov.util.ResponseHeaderCreator; import org.egov.web.models.FiscalEvent; import org.egov.web.models.FiscalEventGetRequest; @@ -16,7 +17,6 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; -import org.egov.service.FiscalEventService; import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java index 6e6c9ba1..388ae20e 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/web/models/FiscalEvent.java @@ -11,7 +11,6 @@ import javax.validation.Valid; import java.util.ArrayList; import java.util.List; -import java.util.UUID; /** * This object captures the fiscal information of external systems. diff --git a/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml b/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml new file mode 100644 index 00000000..b700b4fd --- /dev/null +++ b/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml @@ -0,0 +1,467 @@ +--- +openapi: 3.0.0 +info: + title: ifix-department-entity-service + version: 0.1.0 +servers: +- url: https:///ifix-department-entity + description: SwaggerHub API Auto Mocking +paths: + /departmentEntity/v1/_create: + post: + tags: + - DepartmentEntity + summary: Create/Add new Department Entity on iFix for a tenant + description: Create/Add new Department Entity on iFix for a tenant + requestBody: + description: Details for the new Department Entity + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentEntityRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentEntityResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/v1/_search: + post: + tags: + - DepartmentEntity + summary: Get Department Entity details. + description: | + Based on the criteria get the list of department entities. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentEntitySearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentEntityResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/hierarchyLevel/v1/_create: + post: + tags: + - DepartmentHierarchyLevel + summary: Create/Add new DepartmentHierarchyLevel on iFix for a tenant + description: Create/Add new DepartmentHierarchyLevel on iFix for a tenant + requestBody: + description: Details for the new DepartmentHierarchyLevel + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /departmentEntity/hierarchyLevel/v1/_search: + post: + tags: + - DepartmentHierarchyLevel + summary: Get DepartmentHierarchyLevel. + description: | + Based on the criteria get the list of Department Hierarchy Levels. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentHierarchyLevelResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + DepartmentEntity: + required: + - children + - code + - hierarchyLevelId + - id + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + departmentId: + type: string + description: Department id from department master + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + children: + type: array + items: + type: string + description: Department Entity ids of the children + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: This object captures the information for department entity + DepartmentEntityRequest: + required: + - departmentEntity + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + description: Department Entity request along with request metadata + DepartmentEntityResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + departmentEntity: + type: array + items: + $ref: '#/components/schemas/DepartmentEntity' + description: Contains the ResponseHeader and the enriched Department Entity information + DepartmentEntitySearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentEntitySearchCriteria' + description: Department Entity search request along with request metadata + DepartmentEntitySearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: Department Entity Ids + items: + maxItems: 50 + type: string + tenantId: + type: string + description: Tenant Id + departmentId: + type: string + description: Department id from department master + code: + type: string + description: Unique the department entity code + name: + type: string + description: Captures the department entity name + level: + type: string + description: Capture the level of department entity + getAncestry: + type: boolean + description: If set to true, it will return all the department entity hierarchy details starting from the root to the specified department entity id. + description: The object contains all the search criteria of Department Entity + DepartmentHierarchyLevel: + required: + - departmentId + - id + - label + - tenantId + type: object + properties: + id: + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + type: string + description: Unique tenant identifier + departmentId: + type: string + description: Department id from department master + label: + type: string + description: Unique department hierarchy level code + example: state, zone, city etc + parent: + type: string + description: Capture the department hierarchy level of the parent id (UUID). If it is the root level it will not have any parent. There can only be one root element for a given department. + nullable: true + level: + type: number + description: The level of current DepartmentHierarchyLevel will be set as 1 greater than it\'s parent\'s + readOnly: true + example: 2 + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: This object captures the information for level of the department hierarchy and it's alias + DepartmentHierarchyLevelRequest: + required: + - departmentHierarchyLevel + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + departmentHierarchyLevel: + $ref: '#/components/schemas/DepartmentHierarchyLevel' + description: Department Hierarchy Level request along with request metadata + DepartmentHierarchyLevelResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + departmentHierarchyLevel: + type: array + items: + $ref: '#/components/schemas/DepartmentHierarchyLevel' + description: Contains the ResponseHeader and the enriched Department Hierarchy Level information + DepartmentHierarchyLevelSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentHierarchyLevelSearchCriteria' + description: Department Hierarchy Level search request along with request metadata + DepartmentHierarchyLevelSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: Department Hierarchy Level Ids + items: + maxItems: 50 + type: string + tenantId: + type: string + description: Tenant Id + departmentId: + type: string + description: Department id from department master + label: + type: string + description: Unique department hierarchy label like state, district, etc. + level: + type: number + description: The level of the department hierarchy level + description: The object contains all the search criteria of Department Hierarchy Level + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/ifix-department-entity-service/pom.xml b/domain-services/ifix-department-entity-service/pom.xml index c7b4a231..b2f340a8 100644 --- a/domain-services/ifix-department-entity-service/pom.xml +++ b/domain-services/ifix-department-entity-service/pom.xml @@ -5,7 +5,7 @@ ifix-department-entity-service jar ifix-department-entity-service - 1.0.0 + 0.1.0 1.8 ${java.version} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java index 91afbe0a..b99275f2 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java @@ -33,7 +33,7 @@ public DepartmentEntity getParent(String childId) { Criteria criteria = Criteria.where("children").all(Collections.singletonList(childId)); Query query = Query.query(criteria); List results = mongoTemplate.find(query, DepartmentEntity.class, "departmentEntity"); - if(!results.isEmpty()) + if (!results.isEmpty()) return results.get(0); return null; } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java index 46dca0f8..20775b46 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityEnrichmentService.java @@ -24,9 +24,9 @@ public void enrichDepartmentEntityData(DepartmentEntityRequest departmentEntityR AuditDetails auditDetails = null; - if(departmentEntity.getAuditDetails() == null){ + if (departmentEntity.getAuditDetails() == null) { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentEntity.getAuditDetails(), true); - }else{ + } else { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentEntity.getAuditDetails(), false); } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java index f489a025..62e7cf90 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentEntityService.java @@ -45,9 +45,9 @@ public DepartmentEntityRequest createDepartmentEntity(DepartmentEntityRequest de public List findAllByCriteria(DepartmentEntitySearchRequest departmentEntitySearchRequest) { departmentEntityValidator.validateSearchDepartmentEntity(departmentEntitySearchRequest); List departmentEntityList = entityRepository.searchEntity(departmentEntitySearchRequest); - if(departmentEntitySearchRequest.getCriteria().isGetAncestry()) { + if (departmentEntitySearchRequest.getCriteria().isGetAncestry()) { List departmentEntityAncestryList = new ArrayList<>(); - for(DepartmentEntity departmentEntity : departmentEntityList) { + for (DepartmentEntity departmentEntity : departmentEntityList) { departmentEntityAncestryList.add(createAncestryFor(departmentEntity)); } return departmentEntityAncestryList; @@ -61,7 +61,7 @@ public DepartmentEntityAncestry createAncestryFor(DepartmentEntity departmentEnt departmentEntityAncestryUtil.createDepartmentEntityAncestryFromDepartmentEntity(departmentEntity); while (hierarchyCount >= 0) { DepartmentEntity parentEntity = entityRepository.getParent(ancestry.getId()); - if(parentEntity == null) + if (parentEntity == null) break; DepartmentEntityAncestry parentAncestry = @@ -72,7 +72,7 @@ public DepartmentEntityAncestry createAncestryFor(DepartmentEntity departmentEnt hierarchyCount--; } - if(hierarchyCount < 0) + if (hierarchyCount < 0) throw new CustomException("MAXIMUM_SUPPORTED_HIERARCHY_EXCEEDED", "Loop to find ancestors " + "exceeded the maximum supported hierarchy. The data might be corrupted."); diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java index d6e42f5e..c9a2c15a 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java @@ -8,7 +8,6 @@ import org.egov.repository.DepartmentHierarchyLevelRepository; import org.egov.tracer.model.CustomException; import org.egov.util.DepartmentEntityUtil; -import org.egov.web.models.DepartmentEntitySearchCriteria; import org.egov.web.models.DepartmentHierarchyLevel; import org.egov.web.models.DepartmentHierarchyLevelRequest; import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; @@ -31,6 +30,7 @@ public class DepartmentHierarchyLevelEnrichmentService { /** * Enrich the Department hierarchy level request + * * @param request */ public void enrichHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest request) { diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java index ae77e799..9a94c5d4 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityAncestryUtil.java @@ -6,7 +6,6 @@ import org.springframework.stereotype.Component; import java.util.ArrayList; -import java.util.Collections; @Component @Slf4j diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java index 134c37f8..d2231615 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityConstant.java @@ -2,7 +2,8 @@ public class DepartmentEntityConstant { - private DepartmentEntityConstant(){} + private DepartmentEntityConstant() { + } public static final String USER_INFO = "USER_INFO"; public static final String TENANT_ID = "TENANT_ID"; @@ -18,7 +19,7 @@ private DepartmentEntityConstant(){} public static final String INVALID_TENANT_ID = "INVALID_TENANT_ID"; public static final String INVALID_DEPARTMENT_ID = "INVALID_DEPARTMENT_ID"; public static final String ERROR_SEARCH_CRITERIA = "SEARCH_CRITERIA"; - public static final String INVALID_HIERARCHY_LEVEL= "INVALID_HIERARCHY_LEVEL"; + public static final String INVALID_HIERARCHY_LEVEL = "INVALID_HIERARCHY_LEVEL"; //Search key parameters public static final String IDS = "Ids"; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java index 1f771f16..fddd18b8 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentEntityUtil.java @@ -19,7 +19,7 @@ public class DepartmentEntityUtil { */ public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); - if(isCreate) + if (isCreate) return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); else return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java index 63e180de..1ac95b3a 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentUtil.java @@ -1,6 +1,5 @@ package org.egov.util; -import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; @@ -28,13 +27,12 @@ public class DepartmentUtil { /** - * * @param tenantId * @param departmentId * @param requestHeader * @return */ - public List getDepartmentFromDepartmentService(String tenantId,String departmentId, RequestHeader requestHeader) { + public List getDepartmentFromDepartmentService(String tenantId, String departmentId, RequestHeader requestHeader) { if (StringUtils.isNotBlank(tenantId) && StringUtils.isNotBlank(departmentId)) { Map departmentValueMap = new HashMap<>(); diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java index add23593..befba2d3 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/GovernmentUtil.java @@ -26,7 +26,6 @@ public class GovernmentUtil { private ServiceRequestRepository serviceRequestRepository; /** - * * @param tenantId * @param requestHeader * @return diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java index c802136b..e1a495c7 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -16,7 +16,7 @@ public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader Long ts = null; if (requestInfo != null) ts = requestInfo.getTs(); - final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String sign = requestInfo.getSignature() != null ? requestInfo.getSignature() : ""; final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; final String responseStatus = success ? "successful" : "failed"; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java index c3dfdd4b..5da358e8 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -45,11 +45,11 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (StringUtils.isEmpty(departmentEntity.getTenantId())) { errorMap.put(DepartmentEntityConstant.TENANT_ID, "Tenant id is missing in request data"); - }else if (departmentEntity.getTenantId().length() < 2 || departmentEntity.getTenantId().length() > 64) { + } else if (departmentEntity.getTenantId().length() < 2 || departmentEntity.getTenantId().length() > 64) { errorMap.put(DepartmentEntityConstant.TENANT_ID, "Tenant id length is invalid. " + "Length range [2-64]"); - }else { - List governments = governmentUtil.getGovernmentFromGovernmentService(departmentEntity.getTenantId(),requestHeader); + } else { + List governments = governmentUtil.getGovernmentFromGovernmentService(departmentEntity.getTenantId(), requestHeader); if (governments.isEmpty()) errorMap.put(DepartmentEntityConstant.INVALID_TENANT_ID, "Tenant id : " + departmentEntity.getTenantId() + " doesn't exist in the system"); @@ -58,7 +58,7 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (StringUtils.isEmpty(departmentEntity.getCode())) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_CODE, "Department entity code" + " is missing in request data"); - }else if (departmentEntity.getCode().length() < 1 || departmentEntity.getCode().length() > 256) { + } else if (departmentEntity.getCode().length() < 1 || departmentEntity.getCode().length() > 256) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_CODE, "Department entity code " + "length is invalid. Length range [2-256]"); } @@ -66,7 +66,7 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (StringUtils.isEmpty(departmentEntity.getName())) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_NAME, "Department entity name" + " is missing in request data"); - }else if (departmentEntity.getName().length() < 1 || departmentEntity.getName().length() > 256) { + } else if (departmentEntity.getName().length() < 1 || departmentEntity.getName().length() > 256) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_ENTITY_NAME, "Department entity name " + "length is invalid. Length range [2-256]"); } @@ -74,7 +74,7 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (departmentEntity.getHierarchyLevel() == null) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id" + " is missing in request data"); - }else if (departmentEntity.getHierarchyLevel() < 1 || departmentEntity.getHierarchyLevel() > 256) { + } else if (departmentEntity.getHierarchyLevel() < 1 || departmentEntity.getHierarchyLevel() > 256) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id " + "length is invalid. Length range [2-256]"); } @@ -86,7 +86,7 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn throw new CustomException(errorMap); } - }else { + } else { throw new CustomException(DepartmentEntityConstant.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java index 84458860..13da16aa 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java @@ -56,7 +56,7 @@ public void validateHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest req } if (StringUtils.isNotBlank(departmentHierarchyLevel.getTenantId())) { - List governments = governmentUtil.getGovernmentFromGovernmentService(departmentHierarchyLevel.getTenantId(),requestHeader); + List governments = governmentUtil.getGovernmentFromGovernmentService(departmentHierarchyLevel.getTenantId(), requestHeader); if (governments.isEmpty()) errorMap.put(DepartmentEntityConstant.INVALID_TENANT_ID, "Tenant id : " + departmentHierarchyLevel.getTenantId() + " doesn't exist in the system"); diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java index 6df8cb9c..7255d70d 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentEntityApiController.java @@ -6,7 +6,10 @@ import org.egov.common.contract.response.ResponseHeader; import org.egov.service.DepartmentEntityService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.DepartmentEntityAbstract; +import org.egov.web.models.DepartmentEntityRequest; +import org.egov.web.models.DepartmentEntityResponse; +import org.egov.web.models.DepartmentEntitySearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -17,7 +20,6 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import java.io.IOException; import java.util.Collections; import java.util.List; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java index 28e4f33c..9aace33a 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/controllers/DepartmentHierarchyLevelApiController.java @@ -6,7 +6,10 @@ import org.egov.common.contract.response.ResponseHeader; import org.egov.service.DepartmentHierarchyLevelService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelRequest; +import org.egov.web.models.DepartmentHierarchyLevelResponse; +import org.egov.web.models.DepartmentHierarchyLevelSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java index 56003207..b27e6db1 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntity.java @@ -3,12 +3,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.*; -import org.egov.common.contract.AuditDetails; import org.springframework.validation.annotation.Validated; import javax.validation.Valid; -import java.math.BigDecimal; -import java.util.ArrayList; import java.util.List; /** diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java index df385482..514fad0e 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAbstract.java @@ -2,14 +2,13 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; -import lombok.*; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; import org.egov.common.contract.AuditDetails; import org.springframework.validation.annotation.Validated; -import javax.validation.Valid; -import java.util.ArrayList; -import java.util.List; - /** * This object captures the information for department entity */ diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java index 3f8a2c1c..9d97a2fe 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityAncestry.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import io.swagger.annotations.ApiModel; import lombok.*; -import org.egov.common.contract.AuditDetails; import org.springframework.validation.annotation.Validated; import javax.validation.Valid; diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java index 2ce350fc..e49892c6 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentEntityResponse.java @@ -7,7 +7,6 @@ import org.springframework.validation.annotation.Validated; import javax.validation.Valid; -import java.util.ArrayList; import java.util.List; /** diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java index 422fd2e7..1ead1484 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevel.java @@ -6,8 +6,6 @@ import org.egov.common.contract.AuditDetails; import org.springframework.validation.annotation.Validated; -import java.math.BigDecimal; - /** * This object captures the information for level of the department hierarchy and it's alias */ diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java index e91f3c02..76d0c85a 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/web/models/DepartmentHierarchyLevelSearchCriteria.java @@ -6,7 +6,6 @@ import org.springframework.validation.annotation.Validated; import javax.validation.Valid; -import java.math.BigDecimal; import java.util.ArrayList; import java.util.List; diff --git a/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml b/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml new file mode 100644 index 00000000..a0fd8f7d --- /dev/null +++ b/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml @@ -0,0 +1,1083 @@ +--- +openapi: 3.0.0 +info: + title: ifix-master-data-service + description: iFIX-Master-Data + version: 0.1.0 +servers: +- url: https:///ifix-master-data-service + description: SwaggerHub API Auto Mocking +paths: + /government/v1/_create: + post: + tags: + - Government + summary: Create/Add new tenant on iFix + description: Create/Add the new tenant + requestBody: + description: Details for the new fiscal event + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/GovernmentRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/GovernmentResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /government/v1/_search: + post: + tags: + - Government + summary: Get the list fiscal events. + description: | + Based on the criteria get the list of events. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/GovernmentSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/GovernmentResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /chartOfAccount/v1/_create: + post: + tags: + - COA + summary: Create/Add new COA on iFix for a tenant + description: Create/Add new COA on iFix for a tenant + requestBody: + description: Details for the new COA + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/COARequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/COAResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /chartOfAccount/v1/_search: + post: + tags: + - COA + summary: Get the list COA. + description: | + Based on the criteria get the list of COA. + requestBody: + description: RequestHeader meta data. + content: + application/json: + schema: + $ref: '#/components/schemas/COASearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/COAResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /department/v1/_create: + post: + tags: + - Department + summary: Create/Add new department on iFix for a tenant + description: Create/Add new department on iFix for a tenant + requestBody: + description: Details for the new department + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /department/v1/_search: + post: + tags: + - Department + summary: Get the list departments. + description: | + Based on the criteria get the list of departments. + requestBody: + description: Details for the department search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/DepartmentSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/DepartmentResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /expenditure/v1/_create: + post: + tags: + - Expenditure + summary: Create/Add new Expenditure on iFix for a tenant + description: Create/Add new Expenditure on iFix for a tenant + requestBody: + description: Details for the new Expenditure + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ExpenditureRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/ExpenditureResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /expenditure/v1/_search: + post: + tags: + - Expenditure + summary: Get the list Expenditure. + description: | + Based on the criteria get the list of Expenditure. + requestBody: + description: Details for the Expenditure search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ExpenditureSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/ExpenditureResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /project/v1/_create: + post: + tags: + - Project + summary: Create/Add new project on iFix for a tenant + description: Create/Add new project on iFix for a tenant + requestBody: + description: Details for the new Project + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectRequest' + required: true + responses: + "202": + description: Request has been accepted for processing + content: + '*/*': + schema: + $ref: '#/components/schemas/ProjectResponse' + "400": + description: Failed to process the request + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + /project/v1/_search: + post: + tags: + - Project + summary: Get the list Project. + description: | + Based on the criteria get the list of Project. + requestBody: + description: Details for the Project search criteria + RequestHeader (meta data of the API). + content: + application/json: + schema: + $ref: '#/components/schemas/ProjectSearchRequest' + required: true + responses: + "200": + description: Successful response + content: + '*/*': + schema: + $ref: '#/components/schemas/ProjectResponse' + "400": + description: Invalid input. + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' + "500": + description: Internal server error + content: + '*/*': + schema: + $ref: '#/components/schemas/ErrorResponse' +components: + schemas: + Government: + required: + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant id(eg- pb) + name: + maxLength: 256 + minLength: 2 + type: string + description: name of the tenant + auditDetails: + $ref: '#/components/schemas/AuditDetails' + attributes: + type: object + description: This object captures the fiscal information of external systems. + ChartOfAccount: + required: + - groupHead + - majorHead + - minorHead + - objectHead + - subHead + - subMajorHead + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + coaCode: + maxLength: 64 + minLength: 1 + type: string + description: Chart of account concatinated string + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + majorHead: + maxLength: 4 + minLength: 4 + type: string + description: Capture the major head code + nullable: false + majorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the major head code name + nullable: false + majorHeadType: + maxLength: 32 + minLength: 2 + type: string + description: Capture the major head code type + example: Revenue + subMajorHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the sub major head code + subMajorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the sub major head code name + minorHead: + maxLength: 3 + minLength: 3 + type: string + description: Capture the minor head code + minorHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the minor head code name + subHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the sub head code + subHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the sub head code name + groupHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the group head code + groupHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the group head code name + objectHead: + maxLength: 2 + minLength: 2 + type: string + description: Capture the object head code + objectHeadName: + maxLength: 64 + minLength: 2 + type: string + description: Capture the object head code name + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the COA data as map + Department: + required: + - code + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique department code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the department + isNodal: + type: boolean + description: If it is nodal department then the value will be true + default: false + parent: + maxLength: 64 + minLength: 1 + type: string + description: parent department id + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the department attributes + Expenditure: + required: + - code + - name + - tenantId + - type + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique expenditure code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the expenditure + type: + type: string + description: Capture the type of the expenditure + enum: + - Scheme + - Non-Scheme + departmentId: + maxLength: 64 + minLength: 1 + type: string + description: Department id from department master + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the Expenditure attributes + DepartmentEntityAttributes: + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + description: The list basic attributes of a department entity that are stored as part of the ancestry list + DepartmentEntity: + required: + - code + - hierarchyLevelId + - id + - name + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + code: + maxLength: 256 + minLength: 1 + type: string + description: Unique the department entity code + name: + maxLength: 256 + minLength: 1 + type: string + description: Captures the department entity name + hierarchyLevel: + maxLength: 256 + minLength: 1 + type: number + description: Capture the level of the given department entity + ancestry: + type: array + items: + $ref: '#/components/schemas/DepartmentEntityAttributes' + description: This object captures the information for department entity + readOnly: true + Project: + required: + - code + - name + - tenantId + type: object + properties: + id: + maxLength: 64 + minLength: 1 + type: string + description: Unique system generated UUID + readOnly: true + tenantId: + maxLength: 64 + minLength: 1 + type: string + description: Unique tenant identifier + code: + maxLength: 64 + minLength: 1 + type: string + description: Capture unique Project code + name: + maxLength: 256 + minLength: 2 + type: string + description: Capture the name of the project + expenditureId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the expenditure id from expenditure master + departmentEntitytId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the department entity id from department entity master + departmentEntity: + $ref: '#/components/schemas/DepartmentEntity' + locationIds: + type: array + description: Capture the location id from location master + items: + type: string + auditDetails: + $ref: '#/components/schemas/AuditDetails' + description: Captures the Project attributes + GovernmentRequest: + required: + - government + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + government: + $ref: '#/components/schemas/Government' + description: Tenant request along with request metadata + GovernmentResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + government: + type: array + items: + $ref: '#/components/schemas/Government' + description: Contains the ResponseHeader and the enriched tenant information + GovernmentSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/GovernmentSearchCriteria' + description: Tenant search request along with request metadata + GovernmentSearchCriteria: + type: object + properties: + Ids: + type: array + description: List of fund ids + items: + maxItems: 50 + type: string + description: The object contains all the search criteria of the tenant + COARequest: + required: + - coa + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + chartOfAccount: + $ref: '#/components/schemas/ChartOfAccount' + description: COA request along with request metadata + COAResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + chartOfAccounts: + type: array + items: + $ref: '#/components/schemas/ChartOfAccount' + description: Contains the ResponseHeader and the enriched COA information + COASearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/COASearchCriteria' + description: COA search request along with request metadata. Defoult operator b/w multiple criteria is AND. + COASearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of COA ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + coaCode: + maxLength: 64 + minLength: 1 + type: string + description: Chart of account concatinated string + majorHead: + maxLength: 4 + minLength: 4 + type: string + description: Search by major head + subMajorHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by sub major head + minorHead: + maxLength: 3 + minLength: 3 + type: string + description: Search by minor head + subHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by sub head + groupHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by group head + objectHead: + maxLength: 2 + minLength: 2 + type: string + description: Search by object head + description: The object contains all the search criteria of the fund + DepartmentRequest: + required: + - department + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + department: + $ref: '#/components/schemas/Department' + description: Department request along with request metadata + DepartmentResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + department: + type: array + items: + $ref: '#/components/schemas/Department' + description: Contains the ResponseHeader and the enriched Department information + DepartmentSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/DepartmentSearchCriteria' + description: Department search request along with request metadata. Defoult operator b/w multiple criteria is AND. + DepartmentSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Department ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by department name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by department code + description: The object contains all the search criteria of the Department + ExpenditureRequest: + required: + - expenditure + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + expenditure: + $ref: '#/components/schemas/Expenditure' + description: Expenditure request along with request metadata + ExpenditureResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + Expenditure: + type: array + items: + $ref: '#/components/schemas/Expenditure' + description: Contains the ResponseHeader and the enriched Expenditure information + ExpenditureSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/ExpenditureSearchCriteria' + description: Expenditure search request along with request metadata. Defoult operator b/w multiple criteria is AND. + ExpenditureSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Expenditure ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by Expenditure name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by Expenditure code + description: The object contains all the search criteria of the Expenditure + ProjectRequest: + required: + - project + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + project: + $ref: '#/components/schemas/Project' + description: Project request along with request metadata + ProjectResponse: + properties: + responseHeader: + $ref: '#/components/schemas/ResponseHeader' + project: + type: array + items: + $ref: '#/components/schemas/Project' + description: Contains the ResponseHeader and the enriched Project information + ProjectSearchRequest: + required: + - criteria + - requestHeader + properties: + requestHeader: + $ref: '#/components/schemas/RequestHeader' + criteria: + $ref: '#/components/schemas/ProjectSearchCriteria' + description: Project search request along with request metadata. Default operator b/w multiple criteria is AND + ProjectSearchCriteria: + required: + - tenantId + type: object + properties: + Ids: + type: array + description: List of Project ids + items: + maxItems: 50 + type: string + tenantId: + maxLength: 64 + minLength: 2 + type: string + description: Tenant Id + name: + maxLength: 256 + minLength: 2 + type: string + description: Search by Project name + code: + maxLength: 64 + minLength: 2 + type: string + description: Search by Project code + expenditureId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the expenditure id from expenditure master + departmentId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the department id from department master + locationId: + maxLength: 64 + minLength: 2 + type: string + description: Capture the location id from location master + description: The object contains all the search criteria of the Project + ErrorResponse: + required: + - ResponseHeader + type: object + properties: + ResponseHeader: + $ref: '#/components/schemas/ResponseHeader' + Errors: + minLength: 1 + type: array + description: Error response array to return multiple error for single request + items: + $ref: '#/components/schemas/Error' + description: All APIs will return ErrorRes in case of failure which will carry ResponseHeader as metadata and Error object as actual representation of error. + ResponseHeader: + type: object + properties: + ts: + type: integer + description: response time in epoch + format: int64 + correlationId: + maxLength: 256 + type: string + description: unique response message id (UUID) - will usually be the correlation id from the server + msgId: + maxLength: 256 + type: string + description: message id of the request + status: + type: string + description: status of request processing + enum: + - SUCCESS + - FAILED + signature: + type: string + description: Hash describing the current Request + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + description: ResponseHeader should be used to carry metadata information about the response from the server. apiId, ver and msgId in ResponseHeader should always correspond to the same values in respective request's RequestHeader. + readOnly: true + Error: + required: + - code + - description + - message + type: object + properties: + code: + type: string + description: Error Code will be service specific error label/code to identiffy the error. Example for error code would be User.NotFound to indicate User Not Found by User/Authentication service. All services must declare their possible Error Codes with brief description in the error response section of their API path. + message: + type: string + description: Human readable error message + description: + type: string + description: technical description of the error which can help developer to debug the error if error is unexpected. + description: Error object will be returned as a part of reponse body in conjunction with ResponseHeader as part of ErrorResponse whenever the request processing status in the ResponseHeader is FAILED. HTTP return in this scenario will usually be HTTP 400. + AuditDetails: + type: object + properties: + createdBy: + type: string + description: UUID (preferred) or userid of the user that created the object + readOnly: true + lastModifiedBy: + type: string + description: UUID (preferred) or userid of the user that last modified the object + readOnly: true + createdTime: + type: integer + description: epoch of the time object is created + format: int64 + readOnly: true + lastModifiedTime: + type: integer + description: epoch of the time object is last modified + format: int64 + readOnly: true + description: Collection of audit related fields used by most models + readOnly: true + RequestHeader: + type: object + properties: + ts: + type: integer + description: time in epoch + format: int64 + nullable: false + version: + maxLength: 64 + minLength: 2 + type: string + description: The version of the API + nullable: false + msgId: + maxLength: 256 + type: string + description: Unique request message id from the caller + userInfo: + $ref: '#/components/schemas/UserInfo' + correlationId: + type: string + readOnly: true + signature: + type: string + description: Hash describing the current RequestHeader + description: RequestHeader should be used to carry meta information about the requests to the server as described in the fields below. All eGov APIs will use requestHeader as a part of the request body to carry this meta information. Some of this information will be returned back from the server as part of the ResponseHeader in the response body to ensure correlation. + UserInfo: + type: object + properties: + uuid: + type: string + description: System Generated User id of the authenticated user. + roles: + type: array + description: List of roles assigned to a user + items: + type: string + tenants: + type: array + description: List of tenants assigned to a user + items: + type: string + attributes: + type: object + description: Capture the user information + readOnly: true diff --git a/domain-services/ifix-master-data-service/pom.xml b/domain-services/ifix-master-data-service/pom.xml index 1c769189..155c9b8e 100644 --- a/domain-services/ifix-master-data-service/pom.xml +++ b/domain-services/ifix-master-data-service/pom.xml @@ -5,7 +5,7 @@ ifix-master-data-service jar ifix-master-data-service - 1.0.0 + 0.1.0 1.8 ${java.version} diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java index 4506e6a0..ca8ebb64 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ChartOfAccountRepository.java @@ -3,17 +3,14 @@ import lombok.extern.slf4j.Slf4j; import org.egov.repository.queryBuilder.ChartOfAccountQueryBuilder; -import org.egov.tracer.model.ServiceCallException; -import org.egov.web.models.*; +import org.egov.web.models.COASearchCriteria; +import org.egov.web.models.ChartOfAccount; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; -import org.springframework.data.mongodb.core.query.Criteria; import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Repository; -import org.springframework.web.client.HttpClientErrorException; import org.springframework.web.client.RestTemplate; -import java.util.Collections; import java.util.List; @Repository @@ -35,6 +32,6 @@ public void save(ChartOfAccount chartOfAccount) { public List search(COASearchCriteria searchCriteria) { Query searchQuery = coaQueryBuilder.buildSearchQuery(searchCriteria); - return (mongoTemplate.find(searchQuery,ChartOfAccount.class)); + return (mongoTemplate.find(searchQuery, ChartOfAccount.class)); } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java index 04fd22a7..3ccd0ca6 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/DepartmentRepository.java @@ -3,7 +3,6 @@ import lombok.extern.slf4j.Slf4j; import org.egov.repository.queryBuilder.DepartmentQueryBuilder; -import org.egov.web.models.ChartOfAccount; import org.egov.web.models.Department; import org.egov.web.models.DepartmentSearchCriteria; import org.springframework.beans.factory.annotation.Autowired; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java index 04aba47c..e3445e07 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/GovernmentRepository.java @@ -1,7 +1,6 @@ package org.egov.repository; import org.egov.web.models.Government; -import org.egov.web.models.GovernmentRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.query.Criteria; @@ -27,7 +26,7 @@ public Government findById(String governmentId) { public List findAllByIdList(List idList) { Query query = new Query(); query.addCriteria(Criteria.where("id").in(idList)); - return mongoTemplate.find(query,Government.class); + return mongoTemplate.find(query, Government.class); } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java index 9ceea556..755911e9 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/ServiceRequestRepository.java @@ -36,11 +36,11 @@ public Object fetchResult(String uri, Object request) { Object response = null; try { response = restTemplate.postForObject(uri, request, Map.class); - }catch(HttpClientErrorException e) { - log.error("External Service threw an Exception: ",e); + } catch (HttpClientErrorException e) { + log.error("External Service threw an Exception: ", e); throw new ServiceCallException(e.getResponseBodyAsString()); - }catch(Exception e) { - log.error("Exception while fetching from searcher: ",e); + } catch (Exception e) { + log.error("Exception while fetching from searcher: ", e); } return response; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java index b5327d12..a9ddf23e 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/COAEnrichmentService.java @@ -4,7 +4,6 @@ import lombok.extern.slf4j.Slf4j; import org.egov.common.contract.AuditDetails; import org.egov.common.contract.request.RequestHeader; -import org.egov.repository.ChartOfAccountRepository; import org.egov.util.MasterDataServiceUtil; import org.egov.validator.ChartOfAccountValidator; import org.egov.web.models.COARequest; @@ -14,7 +13,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.List; import java.util.UUID; @Service @@ -26,6 +24,7 @@ public class COAEnrichmentService { @Autowired private ChartOfAccountValidator chartOfAccountValidator; + /** * Enrich the COA create request with COA code, id and audit details. * @@ -45,9 +44,9 @@ public void enrichCreatePost(COARequest coaRequest) { * else insert as fresh record */ - if(chartOfAccount.getAuditDetails() == null){ + if (chartOfAccount.getAuditDetails() == null) { auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), chartOfAccount.getAuditDetails(), true); - }else{ + } else { auditDetails = mdsUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), chartOfAccount.getAuditDetails(), false); } @@ -57,7 +56,7 @@ public void enrichCreatePost(COARequest coaRequest) { } private COASearchCriteria createCOASearchCriteria(ChartOfAccount chartOfAccount) { - COASearchCriteria searchCriteria = new COASearchCriteria(); + COASearchCriteria searchCriteria = new COASearchCriteria(); searchCriteria.setTenantId(chartOfAccount.getTenantId()); searchCriteria.setCoaCode(chartOfAccount.getCoaCode()); return searchCriteria; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java index 28de58b2..6e7dc351 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ChartOfAccountService.java @@ -37,6 +37,7 @@ public class ChartOfAccountService { /** * upsert a COA in the Master data system. + * * @param coaRequest * @return */ @@ -51,6 +52,7 @@ public COARequest chartOfAccountV1CreatePost(COARequest coaRequest) { /** * Search the Chart of Account based on search criteria + * * @param coaSearchRequest * @return */ diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java index cb93f4a4..f295c4b6 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/DepartmentEnrichmentService.java @@ -5,7 +5,10 @@ import org.egov.common.contract.AuditDetails; import org.egov.common.contract.request.RequestHeader; import org.egov.util.MasterDataServiceUtil; -import org.egov.web.models.*; +import org.egov.web.models.Department; +import org.egov.web.models.DepartmentRequest; +import org.egov.web.models.DepartmentSearchCriteria; +import org.egov.web.models.DepartmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; @@ -19,7 +22,8 @@ public class DepartmentEnrichmentService { MasterDataServiceUtil enrichAuditDetails; /** - * Enrich the department search request + * Enrich the department search request + * * @param searchRequest */ public void enrichSearchPost(DepartmentSearchRequest searchRequest) { @@ -37,9 +41,9 @@ public void enrichDepartmentData(DepartmentRequest departmentRequest) { AuditDetails auditDetails = null; - if(department.getAuditDetails() == null){ + if (department.getAuditDetails() == null) { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), department.getAuditDetails(), true); - }else{ + } else { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), department.getAuditDetails(), false); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java index 4e056a46..0157c2ee 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentEnrichmentService.java @@ -3,15 +3,11 @@ import org.egov.common.contract.AuditDetails; import org.egov.common.contract.request.RequestHeader; import org.egov.util.MasterDataServiceUtil; -import org.egov.validator.GovernmentValidator; -import org.egov.web.models.ChartOfAccount; import org.egov.web.models.Government; import org.egov.web.models.GovernmentRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.UUID; - @Component public class GovernmentEnrichmentService { @@ -24,9 +20,9 @@ public void enrichGovernmentData(GovernmentRequest governmentRequest) { AuditDetails auditDetails = null; - if(government.getAuditDetails() == null){ + if (government.getAuditDetails() == null) { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), government.getAuditDetails(), true); - }else{ + } else { auditDetails = enrichAuditDetails.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), government.getAuditDetails(), false); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java index 1c4438b4..d20b5fa8 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/GovernmentService.java @@ -1,23 +1,15 @@ package org.egov.service; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import lombok.extern.slf4j.Slf4j; import org.egov.producer.Producer; import org.egov.repository.GovernmentRepository; -import org.egov.tracer.model.ServiceCallException; import org.egov.validator.GovernmentValidator; import org.egov.web.models.Government; import org.egov.web.models.GovernmentRequest; import org.egov.web.models.GovernmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; import org.springframework.stereotype.Service; -import org.springframework.web.client.HttpClientErrorException; -import org.springframework.web.client.RestTemplate; import java.util.List; -import java.util.Map; @Service public class GovernmentService { diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java index 01410445..831ca739 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java @@ -61,7 +61,7 @@ private JsonNode createDepartmentEntitySearchRequest(RequestHeader requestHeader } private DepartmentEntity getCurrentDepartmentEntity(JsonNode departmentEntityDetails) { - while(departmentEntityDetails.get("children").size() != 0) { + while (departmentEntityDetails.get("children").size() != 0) { departmentEntityDetails = departmentEntityDetails.get("children").get(0); } DepartmentEntity departmentEntity = DepartmentEntity.builder() @@ -84,7 +84,7 @@ private List createAncestryArrayFor(JsonNode departm .hierarchyLevel(departmentEntityDetails.get("hierarchyLevel").asInt()) .build(); ancestry.add(departmentEntityAttributes); - if(departmentEntityDetails.get("children").size() != 0) + if (departmentEntityDetails.get("children").size() != 0) departmentEntityDetails = departmentEntityDetails.get("children").get(0); else departmentEntityDetails = null; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java index 8e888bc5..a6bbdd88 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectEnrichmentService.java @@ -3,7 +3,9 @@ import org.egov.common.contract.AuditDetails; import org.egov.common.contract.request.RequestHeader; import org.egov.util.MasterDataServiceUtil; -import org.egov.web.models.*; +import org.egov.web.models.DepartmentEntity; +import org.egov.web.models.Project; +import org.egov.web.models.ProjectRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -27,10 +29,10 @@ public void enrichProjectData(ProjectRequest projectRequest) { AuditDetails auditDetails = null; - if(project.getAuditDetails() == null){ + if (project.getAuditDetails() == null) { auditDetails = enrichAuditDetails .enrichAuditDetails(requestHeader.getUserInfo().getUuid(), project.getAuditDetails(), true); - }else{ + } else { auditDetails = enrichAuditDetails .enrichAuditDetails(requestHeader.getUserInfo().getUuid(), project.getAuditDetails(), false); } @@ -43,7 +45,7 @@ private void addDepartmentEntityDetails(ProjectRequest projectRequest) { Project project = projectRequest.getProject(); DepartmentEntity departmentEntity = projectDepartmentEntityIntegration.getDepartmentEntityForId(projectRequest.getRequestHeader(), - project.getTenantId(), project.getDepartmentEntitytId()); + project.getTenantId(), project.getDepartmentEntitytId()); project.setDepartmentEntity(departmentEntity); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java index cb07b814..25910108 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/CoaUtil.java @@ -3,12 +3,13 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; -import org.apache.kafka.common.protocol.types.Field; import org.egov.common.contract.request.RequestHeader; import org.egov.config.MasterDataServiceConfiguration; -import org.egov.repository.ChartOfAccountRepository; import org.egov.repository.ServiceRequestRepository; -import org.egov.web.models.*; +import org.egov.web.models.ChartOfAccount; +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentSearchCriteria; +import org.egov.web.models.GovernmentSearchRequest; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -37,12 +38,12 @@ public class CoaUtil { public List searchTenants(RequestHeader requestHeader, ChartOfAccount chartOfAccount) { GovernmentSearchRequest govtSearchRequest = createSearchTenantRequest(requestHeader, chartOfAccount); String url = createSearchTenantUrl(); - Object response = searchRequestRepository.fetchResult(url,govtSearchRequest); - if(response != null){ - LinkedHashMap linkedHashMap = (LinkedHashMap) response; - List governments = (List) linkedHashMap.get("government"); - return governments; - } + Object response = searchRequestRepository.fetchResult(url, govtSearchRequest); + if (response != null) { + LinkedHashMap linkedHashMap = (LinkedHashMap) response; + List governments = (List) linkedHashMap.get("government"); + return governments; + } return Collections.emptyList(); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java index 72cc844d..ab310451 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ExpenditureUtil.java @@ -10,7 +10,6 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java index f24ac427..4699e323 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/MasterDataServiceUtil.java @@ -2,7 +2,6 @@ import org.egov.common.contract.AuditDetails; -import org.egov.web.models.ChartOfAccount; import org.springframework.stereotype.Component; @Component @@ -17,7 +16,7 @@ public class MasterDataServiceUtil { */ public AuditDetails enrichAuditDetails(String by, AuditDetails auditDetails, Boolean isCreate) { Long time = System.currentTimeMillis(); - if(isCreate) + if (isCreate) return AuditDetails.builder().createdBy(by).lastModifiedBy(by).createdTime(time).lastModifiedTime(time).build(); else return AuditDetails.builder().createdBy(auditDetails.getCreatedBy()).lastModifiedBy(by) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java index afe64b92..24807397 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/util/ResponseHeaderCreator.java @@ -15,7 +15,7 @@ public ResponseHeader createResponseHeaderFromRequestHeader(final RequestHeader Long ts = null; if (requestInfo != null) ts = requestInfo.getTs(); - final String sign = requestInfo.getSignature()!= null ? requestInfo.getSignature() : "" ; + final String sign = requestInfo.getSignature() != null ? requestInfo.getSignature() : ""; final String msgId = requestInfo != null ? requestInfo.getMsgId() : ""; final String responseStatus = success ? "successful" : "failed"; diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java index 72198140..7954cb15 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ChartOfAccountValidator.java @@ -187,7 +187,7 @@ public void validateSearchPost(COASearchRequest coaSearchRequest) { errorMap.put("SUB_MAJOR_HEAD_CODE_LENGTH", "Sub major head Code should be of length 2"); } if (StringUtils.isNotBlank(searchCriteria.getCoaCode()) && (searchCriteria.getCoaCode().length() < 1 - || searchCriteria.getCoaCode().length()>64) ) { + || searchCriteria.getCoaCode().length() > 64)) { errorMap.put("SUB_MAJOR_HEAD_CODE_LENGTH", "Sub major head Code should be of length 2"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java index 926329d0..9a35ad3e 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/DepartmentValidator.java @@ -7,7 +7,10 @@ import org.egov.tracer.model.CustomException; import org.egov.util.MasterDataConstants; import org.egov.util.TenantUtil; -import org.egov.web.models.*; +import org.egov.web.models.Department; +import org.egov.web.models.DepartmentRequest; +import org.egov.web.models.DepartmentSearchCriteria; +import org.egov.web.models.DepartmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -96,14 +99,14 @@ public void validateCreateRequestData(DepartmentRequest departmentRequest) { if (StringUtils.isEmpty(department.getCode())) { errorMap.put(MasterDataConstants.DEPARTMENT_CODE, "Department code is missing in request data"); - }else if (department.getCode().length() < 1 || department.getCode().length() > 64) { + } else if (department.getCode().length() < 1 || department.getCode().length() > 64) { errorMap.put(MasterDataConstants.DEPARTMENT_CODE, "Department code length is invalid. " + "Length range [1-64]"); } if (StringUtils.isEmpty(department.getCode())) { errorMap.put(MasterDataConstants.DEPARTMENT_NAME, "Department name is missing in request data"); - }else if (department.getCode().length() < 1 || department.getCode().length() > 64) { + } else if (department.getCode().length() < 1 || department.getCode().length() > 64) { errorMap.put(MasterDataConstants.DEPARTMENT_NAME, "Department name length is invalid. " + "Length range [1-64]"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java index a4e7e7af..82a69668 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ExpenditureValidator.java @@ -40,7 +40,7 @@ public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditur if (StringUtils.isEmpty(criteria.getTenantId())) { throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); - }else if (criteria.getTenantId().length() < 2 || criteria.getTenantId().length() > 64) { + } else if (criteria.getTenantId().length() < 2 || criteria.getTenantId().length() > 64) { throw new CustomException(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + "Length range [2-64]"); } @@ -53,11 +53,11 @@ public void validateExpenditureSearchRequest(ExpenditureSearchRequest expenditur if (!StringUtils.isEmpty(criteria.getCode()) && (criteria.getCode().length() < 2 || criteria.getCode().length() > 64)) { - throw new CustomException(MasterDataConstants.EXPENDITURE_CODE, "Expenditure code length is invalid. " + - "Length range [2-64]"); + throw new CustomException(MasterDataConstants.EXPENDITURE_CODE, "Expenditure code length is invalid. " + + "Length range [2-64]"); } - }else { + } else { throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } } @@ -116,7 +116,7 @@ public void validateExpenditureCreateRequest(ExpenditureRequest expenditureReque } //type - if(expenditure.getType() == null){ + if (expenditure.getType() == null) { errorMap.put(MasterDataConstants.EXPENDITURE_TYPE, "Expenditure type is missing in request data"); } //department id diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java index 54790ec1..2423e2cb 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/GovernmentValidator.java @@ -31,13 +31,13 @@ public void validateGovernmentRequestData(GovernmentRequest governmentRequest) { Government government = governmentRequest.getGovernment(); if (StringUtils.isEmpty(government.getId())) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government Id (Tenant id) is missing in request data"); - }else if (government.getId().length() < 1 || government.getId().length() > 64) { + } else if (government.getId().length() < 1 || government.getId().length() > 64) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id length is invalid."); } if (StringUtils.isEmpty(government.getName())) { throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name is missing in request data"); - }else if (government.getName().length() < 2 || government.getName().length() > 256) { + } else if (government.getName().length() < 2 || government.getName().length() > 256) { throw new CustomException(MasterDataConstants.GOVERNMENT_NAME, "Government name length is invalid"); } @@ -45,7 +45,7 @@ public void validateGovernmentRequestData(GovernmentRequest governmentRequest) { if (existingGovernment != null) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Duplicate government id"); } - }else { + } else { throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } } @@ -58,7 +58,7 @@ public void validateGovernmentSearchRequestData(GovernmentSearchRequest governme if (criteria == null) { throw new CustomException("INVALID_SEARCH_CRITERIA", "Search criteria is missing"); - }else if (criteria.getIds() == null || criteria.getIds().isEmpty()) { + } else if (criteria.getIds() == null || criteria.getIds().isEmpty()) { throw new CustomException(MasterDataConstants.GOVERNMENT_ID, "Government id list are missing"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java index 6bf2632e..6a36c6b4 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java @@ -16,7 +16,6 @@ import java.util.Collections; import java.util.HashMap; -import java.util.List; import java.util.Map; @Component @@ -111,23 +110,23 @@ public void validateProjectCreateRequest(ProjectRequest projectRequest) { if (StringUtils.isEmpty(project.getTenantId())) { errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id is missing in request data"); - }else if (project.getTenantId().length() < 2 || project.getTenantId().length() > 64) { + } else if (project.getTenantId().length() < 2 || project.getTenantId().length() > 64) { errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id length is invalid. " + "Length range [2-64]"); - }else if (!tenantUtil.validateTenant(project.getTenantId(),requestHeader)) { - errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id : " + project.getTenantId() - + " doesn't exist in the system"); + } else if (!tenantUtil.validateTenant(project.getTenantId(), requestHeader)) { + errorMap.put(MasterDataConstants.TENANT_ID, "Tenant id : " + project.getTenantId() + + " doesn't exist in the system"); } if (StringUtils.isEmpty(project.getCode())) { errorMap.put(MasterDataConstants.PROJECT_CODE, "Project code is missing in request data"); - }else if (project.getCode().length() < 1 || project.getCode().length() > 64) { + } else if (project.getCode().length() < 1 || project.getCode().length() > 64) { errorMap.put(MasterDataConstants.PROJECT_CODE, "Project code length is invalid. Length range [1-64]"); } if (StringUtils.isEmpty(project.getName())) { errorMap.put(MasterDataConstants.PROJECT_NAME, "Project name is missing in request data"); - }else if (project.getName().length() < 1 || project.getName().length() > 64) { + } else if (project.getName().length() < 1 || project.getName().length() > 64) { errorMap.put(MasterDataConstants.PROJECT_NAME, "Project name length is invalid. Length range [1-64]"); } @@ -159,7 +158,7 @@ public void validateProjectCreateRequest(ProjectRequest projectRequest) { if (!errorMap.isEmpty()) { throw new CustomException(errorMap); } - }else { + } else { throw new CustomException(MasterDataConstants.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java index ed416b46..e0352cd3 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ChartOfAccountApiController.java @@ -53,7 +53,7 @@ public ResponseEntity chartOfAccountV1CreatePost(@ApiParam(value = COAResponse coaResponse = COAResponse.builder().responseHeader(responseHeader) .chartOfAccounts(Collections.singletonList(coaRequest.getChartOfAccount())).build(); - return new ResponseEntity(coaResponse,HttpStatus.ACCEPTED); + return new ResponseEntity(coaResponse, HttpStatus.ACCEPTED); } @RequestMapping(value = "/_search", method = RequestMethod.POST) @@ -63,7 +63,7 @@ public ResponseEntity chartOfAccountV1SearchPost(@ApiParam(value = COAResponse coaResponse = COAResponse.builder().responseHeader(responseHeader) .chartOfAccounts(chartOfAccounts).build(); - return new ResponseEntity(coaResponse,HttpStatus.OK); + return new ResponseEntity(coaResponse, HttpStatus.OK); } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java index 15234d81..2eb7c8a5 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/DepartmentApiController.java @@ -6,7 +6,10 @@ import org.egov.common.contract.response.ResponseHeader; import org.egov.service.DepartmentService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.Department; +import org.egov.web.models.DepartmentRequest; +import org.egov.web.models.DepartmentResponse; +import org.egov.web.models.DepartmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -17,7 +20,6 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import java.io.IOException; import java.util.Collections; import java.util.List; @@ -67,7 +69,7 @@ public ResponseEntity departmentV1SearchPost(@ApiParam(value ResponseHeader responseHeader = responseHeaderCreator.createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); DepartmentResponse departmentResponse = DepartmentResponse.builder().responseHeader(responseHeader) .department(departments).build(); - return new ResponseEntity(departmentResponse,HttpStatus.OK); + return new ResponseEntity(departmentResponse, HttpStatus.OK); } } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java index a055969c..9c47964f 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/GovernmentApiController.java @@ -6,7 +6,10 @@ import org.egov.common.contract.response.ResponseHeader; import org.egov.service.GovernmentService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.Government; +import org.egov.web.models.GovernmentRequest; +import org.egov.web.models.GovernmentResponse; +import org.egov.web.models.GovernmentSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -49,7 +52,7 @@ public GovernmentApiController(ObjectMapper objectMapper, HttpServletRequest req @RequestMapping(value = "/_create", method = RequestMethod.POST) public ResponseEntity governmentV1CreatePost(@ApiParam(value = "Details for the governmet master data creation, RequestHeader (meta data of the API).", required = true) - @Valid @RequestBody GovernmentRequest body) { + @Valid @RequestBody GovernmentRequest body) { GovernmentRequest governmentRequest = governmentService.addGovernment(body); diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java index fe87aea0..97dfe003 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/controllers/ProjectApiController.java @@ -4,10 +4,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import io.swagger.annotations.ApiParam; import org.egov.common.contract.response.ResponseHeader; -import org.egov.repository.ProjectRepository; import org.egov.service.ProjectService; import org.egov.util.ResponseHeaderCreator; -import org.egov.web.models.*; +import org.egov.web.models.Project; +import org.egov.web.models.ProjectRequest; +import org.egov.web.models.ProjectResponse; +import org.egov.web.models.ProjectSearchRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; @@ -18,7 +20,6 @@ import javax.servlet.http.HttpServletRequest; import javax.validation.Valid; -import java.io.IOException; import java.util.Collections; import java.util.List; @@ -55,7 +56,7 @@ public ResponseEntity projectV1CreatePost(@ApiParam(value = "De ProjectRequest projectRequest = projectService.createProject(body); ResponseHeader responseHeader = responseHeaderCreator - .createResponseHeaderFromRequestHeader(body.getRequestHeader(),true); + .createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); ProjectResponse projectResponse = ProjectResponse.builder().responseHeader(responseHeader) .project(Collections.singletonList(projectRequest.getProject())).build(); @@ -70,12 +71,12 @@ public ResponseEntity projectV1CreatePost(@ApiParam(value = "De @RequestMapping(value = "/_search", method = RequestMethod.POST) public ResponseEntity projectV1SearchPost(@ApiParam(value = "Details for the Project search " + "criteria RequestHeader (meta data of the API).", required = true) - @Valid @RequestBody ProjectSearchRequest body) { + @Valid @RequestBody ProjectSearchRequest body) { List projectList = projectService.findAllByCriteria(body); ResponseHeader responseHeader = responseHeaderCreator - .createResponseHeaderFromRequestHeader(body.getRequestHeader(),true); + .createResponseHeaderFromRequestHeader(body.getRequestHeader(), true); ProjectResponse projectResponse = ProjectResponse.builder().responseHeader(responseHeader) .project(projectList).build(); diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java index 20cb48b3..d3b8da94 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/COASearchCriteria.java @@ -62,7 +62,7 @@ public COASearchCriteria addIdsItem(String idsItem) { return this; } - public boolean isEmpty(){ + public boolean isEmpty() { return (StringUtils.isBlank(tenantId) && StringUtils.isBlank(majorHead) && StringUtils.isBlank(minorHead) && StringUtils.isBlank(subHead) && StringUtils.isBlank(subMajorHead) && StringUtils.isBlank(groupHead) && StringUtils.isBlank(objectHead) && (ids == null || ids.isEmpty()) && StringUtils.isBlank(coaCode)); diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java index 2336a503..88d93eb3 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentEntityAttributes.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import lombok.*; -import org.egov.common.contract.AuditDetails; @Getter @Setter diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java index b5cb8914..e5306f91 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/DepartmentSearchCriteria.java @@ -44,7 +44,8 @@ public DepartmentSearchCriteria addIdsItem(String idsItem) { this.ids.add(idsItem); return this; } - public boolean isEmpty(){ + + public boolean isEmpty() { return (StringUtils.isBlank(tenantId) && StringUtils.isBlank(name) && StringUtils.isBlank(code) && (ids == null || ids.isEmpty())); } diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java index 6dd97477..36c08dde 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/Government.java @@ -6,9 +6,6 @@ import org.egov.common.contract.AuditDetails; import org.springframework.validation.annotation.Validated; -import javax.validation.constraints.NotNull; -import javax.validation.constraints.Size; - /** * This object captures the fiscal information of external systems. */ From 7e117c653e448a9048b432dcc8cfee70c7490bb1 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Sat, 4 Sep 2021 16:00:26 +0530 Subject: [PATCH 29/67] Druid config (#56) * Added transformSpec * Updated JMeter test with csv Co-authored-by: rushang7-eGov --- .../druid-ingestion-config.json | 42 ++++++++++++++++++- .../Fiscal-Event-Request.jmx | 37 +++++++++------- 2 files changed, 64 insertions(+), 15 deletions(-) diff --git a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json index b18663e1..4508f260 100644 --- a/domain-services/fiscal-event-post-processor/druid-ingestion-config.json +++ b/domain-services/fiscal-event-post-processor/druid-ingestion-config.json @@ -21,6 +21,30 @@ "column": "eventTime", "format": "millis" }, + "transformSpec": { + "transforms": [ + { + "type": "expression", + "name": "bill", + "expression": "if(\"eventType\" == 'BILL', \"amount\", 0)" + }, + { + "type": "expression", + "name": "receipt", + "expression": "if(\"eventType\" == 'RECEIPT', \"amount\", 0)" + }, + { + "type": "expression", + "name": "payment", + "expression": "if(\"eventType\" == 'PAYMENT', \"amount\", 0)" + }, + { + "type": "expression", + "name": "demand", + "expression": "if(\"eventType\" == 'DEMAND', \"amount\", 0)" + } + ] + }, "dimensionsSpec": { "dimensions": [ "id", @@ -129,8 +153,24 @@ "project.id", "project.code", - "project.name" + "project.name", + { + "name": "bill", + "type": "double" + }, + { + "name": "receipt", + "type": "double" + }, + { + "name": "demand", + "type": "double" + }, + { + "name": "payment", + "type": "double" + } ] }, "granularitySpec": { diff --git a/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx b/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx index d8063fe6..78b3a548 100644 --- a/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx +++ b/domain-services/fiscal-event-service/Fiscal-Event-Request.jmx @@ -37,23 +37,20 @@ "ts": 1629286294000, "version": "v1", "msgId": "", - "signature": "", - "userInfo": { - "uuid": "e4fd96e8-3b6b-4e36-9503-0f14a01af39d" - } + "signature": "" }, "fiscalEvent": { - "tenantId": "pb", - "projectId": "74c62227-d91a-4301-9592-2c9178af002d", - "eventType": "RECEIPT", - "referenceId": "8fade363-0ee6-46cb-a3ab-90e852f2de0d", - "eventTime": "1603423893000", + "tenantId": "${tenantId}", + "projectId": "${projectId}", + "eventType": "${eventType}", + "referenceId": "${referenceId}", + "eventTime": ${eventTime}, "amountDetails": [ { - "amount": 540, - "fromBillingPeriod": "1609459693000", - "toBillingPeriod": "1599400181000", - "coaId": "23d38475-80a4-486d-9946-da890e165dfa" + "amount": ${amount}, + "fromBillingPeriod": ${fromBillingPeriod}, + "toBillingPeriod": ${toBillingPeriod}, + "coaId": "${coaId}" } ] } @@ -85,7 +82,7 @@ Authorization - Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzIzMDQ4NjcsImlhdCI6MTYyOTcxMjg2NywianRpIjoiYzM5MmRkODctNWI4MC00ZjVkLWIxNGQtNjk3ZDExNGEzNWUzIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.Hby4BbwMvecANTo-JOefpaaNhNEw1YxcCRfc8bCNxzr49PZLiz7RZZx5f11Df4ifSMErQBtyr6Xb_PDyQXtvJl10BHofznf-dciyVDIDy6uJgzUhXZJTQq6aZFIgO-WEsDvfCFuBEEoLrxB3vl5L8fATRqS3g1TEItp_uq5tKleCl05vH96MuR1soOZjH-ow6qZMSRspqU0jGwbeG-SCyMFfFWD-z123LRrXy4psTmUv4v0d4Z7QHfonctjA3Bo99uQ6GUAQ8QhgBWkwpG5hj4x8y6ZAbeCUP-LgNvXQKSms1qvsteGsGaaNuUco-jqxK7fsMVpJ69RzCCNDmFZByA + Bearer token @@ -165,6 +162,18 @@ + + /path-to-csv/fiscal-event-request-csv.csv + + tenantId,projectId,eventType,referenceId,eventTime,amount,fromBillingPeriod,toBillingPeriod,coaId + true + , + false + false + true + shareMode.all + + From 8987f7e61f6affb7e414e849186febacdbab9f08 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Mon, 6 Sep 2021 12:24:06 +0530 Subject: [PATCH 30/67] documentation link and postman collection (#57) * documentation link and postman collection * link fix * Update README.md Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov Co-authored-by: rushang7-eGov --- .../fiscal-event-service/README.md | 4 +- .../ifix-fiscal-event.postman_collection.json | 237 ++++++++++++++++++ 2 files changed, 240 insertions(+), 1 deletion(-) create mode 100644 domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json diff --git a/domain-services/fiscal-event-service/README.md b/domain-services/fiscal-event-service/README.md index 3047cadc..dfdeb069 100644 --- a/domain-services/fiscal-event-service/README.md +++ b/domain-services/fiscal-event-service/README.md @@ -1 +1,3 @@ -# Fiscal-Event-Service \ No newline at end of file +# Fiscal-Event-Service + +## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml) diff --git a/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json b/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json new file mode 100644 index 00000000..7adb6dfd --- /dev/null +++ b/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json @@ -0,0 +1,237 @@ +{ + "info": { + "_postman_id": "9d3c2923-ae2b-4010-b5fe-5e419e646748", + "name": "ifix-fiscal-event", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "fiscal-event-push", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"fiscalEvent\": {\r\n \"tenantId\": \"pb\",\r\n \"projectId\": \"69b1ed7c-c585-4731-b22d-469a26badeb9\",\r\n \"eventType\": \"Appropriation\",\r\n \"eventTime\": 1628177497000,\r\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\r\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\r\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\r\n \"amountDetails\": [\r\n {\r\n \"amount\": 10234.5,\r\n \"coaId\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\r\n \"fromBillingPeriod\": 1622907239000,\r\n \"toBillingPeriod\": 1628177643000\r\n }\r\n ],\r\n \"attributes\": {}\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8031/fiscal-event-service/events/v1/_push", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8031", + "path": [ + "fiscal-event-service", + "events", + "v1", + "_push" + ] + } + }, + "response": [] + }, + { + "name": "fiscal-event-push dev", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"fiscalEvent\": {\r\n \"tenantId\": \"pb\",\r\n \"projectId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac5\",\r\n \"eventType\": \"Bill\",\r\n \"eventTime\": 1629286294000,\r\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\r\n \"amountDetails\": [\r\n {\r\n \"amount\": 10234.5,\r\n \"coaId\": \"50cc5634-6cc3-456b-ae33-e40741128cde\",\r\n \"fromBillingPeriod\": 1622907239000,\r\n \"toBillingPeriod\": 1628177643000\r\n }\r\n ],\r\n \"attributes\": {}\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8031/fiscal-event-service/events/v1/_push", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8031", + "path": [ + "fiscal-event-service", + "events", + "v1", + "_push" + ] + } + }, + "response": [] + }, + { + "name": "fiscal-even-search", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"pb\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8031", + "path": [ + "fiscal-event-service", + "events", + "v1", + "_search" + ] + } + }, + "response": [ + { + "name": "fiscal-even-search", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"PB\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8031", + "path": [ + "fiscal-event-service", + "events", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Mon, 30 Aug 2021 08:43:47 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"fiscalEvent\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"tenantId\": \"PB\",\n \"projectId\": null,\n \"eventType\": \"APPROPRIATION\",\n \"ingestionTime\": null,\n \"eventTime\": 1628177497000,\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\n \"amountDetails\": [\n {\n \"id\": null,\n \"amount\": 10234.5,\n \"coaId\": null,\n \"fromBillingPeriod\": 1622907239000,\n \"toBillingPeriod\": 1628177643000\n }\n ],\n \"auditDetails\": null,\n \"attributes\": {}\n }\n ]\n}" + }, + { + "name": "fiscal-even-search", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"PB\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8031", + "path": [ + "fiscal-event-service", + "events", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Tue, 31 Aug 2021 08:22:54 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"fiscalEvent\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"tenantId\": \"PB\",\n \"projectId\": \"69b1ed7c-c585-4731-b22d-469a26badeb9\",\n \"eventType\": \"APPROPRIATION\",\n \"ingestionTime\": null,\n \"eventTime\": 1628177497000,\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\n \"amountDetails\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"amount\": 10234.5,\n \"coaId\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\n \"fromBillingPeriod\": 1622907239000,\n \"toBillingPeriod\": 1628177643000\n }\n ],\n \"auditDetails\": null,\n \"attributes\": {}\n }\n ]\n}" + } + ] + } + ] +} \ No newline at end of file From bf6167c28a730e9c972ee92dcc81b403fe7eafbc Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Mon, 6 Sep 2021 12:34:48 +0530 Subject: [PATCH 31/67] Doc add (#58) * Added the postman and documentation link * redocly link fix * redocly link fix1 * redocly link Co-authored-by: pintu-eGov Co-authored-by: rahu-eGov --- .../ifix-master-data-service/README.md | 2 + .../ifix-master-data.postman_collection.json | 1241 +++++++++++++++++ 2 files changed, 1243 insertions(+) create mode 100644 domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json diff --git a/domain-services/ifix-master-data-service/README.md b/domain-services/ifix-master-data-service/README.md index 91f3e06d..9e509b06 100644 --- a/domain-services/ifix-master-data-service/README.md +++ b/domain-services/ifix-master-data-service/README.md @@ -1,5 +1,7 @@ # iFIX-Master-Data-Service +## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml) + ## Connect to MongoDB through Playground pod Check the correct running mongodb pod and execute the below command ``` diff --git a/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json b/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json new file mode 100644 index 00000000..64d03c02 --- /dev/null +++ b/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json @@ -0,0 +1,1241 @@ +{ + "info": { + "_postman_id": "fee8e3c9-0f45-46b3-967a-c8d0de45665e", + "name": "ifix-master-data", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Chart of account", + "item": [ + { + "name": "Create_COA", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"pb\",\r\n \"majorHead\": \"824\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"37\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://ifix-qa.ifix.org.in/ifix-master-data/chartOfAccount/v1/_create", + "protocol": "https", + "host": [ + "ifix-qa", + "ifix", + "org", + "in" + ], + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_create" + ] + } + }, + "response": [ + { + "name": "Create_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8988\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_create" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Fri, 06 Aug 2021 08:51:00 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\n \"coaCode\": \"8988-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8988\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628239860279,\n \"lastModifiedTime\": 1628239860279\n }\n }\n ]\n}" + }, + { + "name": "Create_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8984\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_create" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Sat, 07 Aug 2021 07:01:56 GMT" + }, + { + "key": "Connection", + "value": "close" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"DUPLICATE_COA_CODE\",\n \"message\": \"This coa code exists in the system\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" + }, + { + "name": "Create_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8983\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_create" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Sat, 07 Aug 2021 14:14:41 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"f064855d-d257-4737-bf52-cc48c4c7ff22\",\n \"coaCode\": \"8983-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8983\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadType\": null,\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628345681440,\n \"lastModifiedTime\": 1628345681440\n }\n }\n ]\n}" + } + ] + }, + { + "name": "Search_COA", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"9545d9a7-0d41-4f70-bb4d-c0c049776855\",\"512db21b-9d2b-4ae4-84d0-da1afe87db13\"\r\n ],\r\n \"tenantId\": \"pb\",\r\n \"subHead\": \"56\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "https://ifix-qa.ifix.org.in/ifix-master-data/chartOfAccount/v1/_search", + "protocol": "https", + "host": [ + "ifix-qa", + "ifix", + "org", + "in" + ], + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_search" + ] + } + }, + "response": [ + { + "name": "Search_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n\r\n \"tenantId\": \"string\",\r\n \"majorHead\": \"123\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 04 Aug 2021 08:15:36 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"20361abb-11ac-4b32-abe1-3abc7e6570db\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628064067597,\n \"lastModifiedTime\": 1628064067597\n }\n }\n ]\n}" + }, + { + "name": "Search_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"string\",\r\n \"majorHead\": \"123\",\r\n \"minorHead\": \"34\",\r\n \"subHead\": \"56\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 04 Aug 2021 08:17:21 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"20361abb-11ac-4b32-abe1-3abc7e6570db\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628064067597,\n \"lastModifiedTime\": 1628064067597\n }\n }\n ]\n}" + }, + { + "name": "Search_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \r\n \"majorHead\": \"123\",\r\n \"minorHead\": \"34\",\r\n \"subHead\": \"56\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_search" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 04 Aug 2021 08:22:43 GMT" + }, + { + "key": "Connection", + "value": "close" + } + ], + "cookie": [], + "body": "{\n \"ResponseInfo\": null,\n \"Errors\": [\n {\n \"code\": \"TENANT_ID\",\n \"message\": \"Tenant id is mandatory\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" + }, + { + "name": "Search_COA", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\"512db21b-9d2b-4ae4-84d0-da1afe87db13\"\r\n ],\r\n \"tenantId\": \"PB\",\r\n \"subHead\": \"56\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "chartOfAccount", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Sat, 07 Aug 2021 07:03:04 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"512db21b-9d2b-4ae4-84d0-da1afe87db13\",\n \"coaCode\": \"8984-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8984\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadType\": null,\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628319687417,\n \"lastModifiedTime\": 1628319687417\n }\n }\n ]\n}" + } + ] + } + ] + }, + { + "name": "Government", + "item": [ + { + "name": "Create_Government", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"government\": {\r\n \"id\": \"pb\",\r\n \"name\": \"Punjab\",\r\n \"attributes\": {}\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/government/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "government", + "v1", + "_create" + ] + } + }, + "response": [ + { + "name": "Create_Government", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"government\": {\r\n \"id\": \"UP\",\r\n \"name\": \"Uttar Pardesh\",\r\n \"attributes\": {}\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/government/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "government", + "v1", + "_create" + ] + } + }, + "status": "Accepted", + "code": 202, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Sat, 07 Aug 2021 14:15:12 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"government\": [\n {\n \"id\": \"UP\",\n \"name\": \"Uttar Pardesh\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628345712790,\n \"lastModifiedTime\": 1628345712790\n },\n \"attributes\": {}\n }\n ]\n}" + } + ] + }, + { + "name": "Search_Government", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"pb\",\"br\",\"hr\",\"up\",\"ka\"\n ]\n }\n}" + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/government/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "government", + "v1", + "_search" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Department", + "item": [ + { + "name": "Search_Department", + "request": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ad3\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8020/ifix-master-data/department/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8020", + "path": [ + "ifix-master-data", + "department", + "v1", + "_search" + ] + } + }, + "response": [ + { + "name": "Search_Department", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data//department/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "", + "department", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Fri, 06 Aug 2021 08:20:56 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"department\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\n \"tenantId\": \"pb\",\n \"code\": \"123\",\n \"name\": \"departmentName\",\n \"isNodal\": false,\n \"parent\": \"parent\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n }\n ]\n}" + }, + { + "name": "Search_Department", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ac2\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data//department/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "", + "department", + "v1", + "_search" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Fri, 06 Aug 2021 08:26:10 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"department\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\n \"tenantId\": \"pb\",\n \"code\": \"123\",\n \"name\": \"departmentName\",\n \"isNodal\": false,\n \"parent\": \"parent\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac2\",\n \"tenantId\": \"pb\",\n \"code\": \"1234\",\n \"name\": \"departmentName1\",\n \"isNodal\": false,\n \"parent\": \"parent1\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n }\n ]\n}" + } + ] + }, + { + "name": "create_department", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzI1NzUwNTEsImlhdCI6MTYyOTk4MzA1MSwianRpIjoiNmZkZTJiMjktY2VmZS00MDFjLWIwNjgtOWE0Y2ViYjM1YzdlIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.JsNvMIt8aQOiw2fnCtMN2a8xniBmH613cJu_MH_POjYL5nLI1ec4j7KA46gMxpKzy_2tL-LZ_snc4YtpertNdIOtoIk4KjH93DtKEnh2gAcuI_dbS4IRjBjyvqojkD0SJ6a3T17FwDLQk60TS9RytynhHQUjzeurC559bLhlTmEp1Q8Z0PtR5JnyjproHtoesVPoxCMq1Yuu5EBG2wcyKPlXnNXmGwt9WmdRaWPJFbhoEl0DxnuNDgBuP1nkB-mxA-nwPhNi90lLr1PUsdJ2xbkeQxekj4cUOf7bUn5ctJa1WcsNs2cjZeT5JJTMt_5FHSOjh1yr4cETN47pe0SrJQ" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"department\": {\n \"tenantId\": \"pb\",\n \"code\": \"DEP-1000\",\n \"name\": \"department-1000\",\n \"isNodal\": false,\n \"parent\": \"parent2\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/department/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "department", + "v1", + "_create" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Expenditure", + "item": [ + { + "name": "Create_Expenditure", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"pb\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_create", + "protocol": "http", + "host": [ + "ifix-dev", + "ifix", + "org", + "in" + ], + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_create" + ] + } + }, + "response": [ + { + "name": "Create_Expenditure", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_create" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 01 Sep 2021 08:40:05 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"expenditure\": [\n {\n \"id\": \"dd3fe84b-f436-4b9d-88be-cfcbf23131f1\",\n \"tenantId\": \"PB\",\n \"code\": \"exp-01\",\n \"name\": \"expenditure one\",\n \"type\": \"Scheme\",\n \"departmentId\": null,\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1630485605296,\n \"lastModifiedTime\": 1630485605296\n }\n }\n ]\n}" + }, + { + "name": "Create_Expenditure", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_create" + ] + } + }, + "status": "OK", + "code": 200, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 01 Sep 2021 08:43:43 GMT" + }, + { + "key": "Keep-Alive", + "value": "timeout=60" + }, + { + "key": "Connection", + "value": "keep-alive" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"expenditure\": [\n {\n \"id\": \"59bce7d2-9c87-4856-89cf-4a1f2ffba55a\",\n \"tenantId\": \"PB\",\n \"code\": \"exp-01\",\n \"name\": \"expenditure one\",\n \"type\": \"Scheme\",\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1630485823004,\n \"lastModifiedTime\": 1630485823004\n }\n }\n ]\n}" + }, + { + "name": "Create_Expenditure", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_create" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Date", + "value": "Wed, 01 Sep 2021 08:44:26 GMT" + }, + { + "key": "Connection", + "value": "close" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"EXPENDITURE_TYPE\",\n \"message\": \"Expenditure type is missing in request data\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" + }, + { + "name": "Create_Expenditure", + "originalRequest": { + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"pb\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_create", + "protocol": "http", + "host": [ + "ifix-dev", + "ifix", + "org", + "in" + ], + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_create" + ] + } + }, + "status": "Bad Request", + "code": 400, + "_postman_previewlanguage": "json", + "header": [ + { + "key": "Date", + "value": "Thu, 02 Sep 2021 08:42:06 GMT" + }, + { + "key": "Content-Type", + "value": "application/json" + }, + { + "key": "Transfer-Encoding", + "value": "chunked" + }, + { + "key": "Connection", + "value": "keep-alive" + }, + { + "key": "Strict-Transport-Security", + "value": "max-age=63072000; includeSubdomains; preload" + }, + { + "key": "X-Lua-Resty-WAF-ID", + "value": "fb1470275dd9fd94e4eb" + }, + { + "key": "x-correlation-id", + "value": "c40f14a7-3951-4ba6-8795-47ce4ac3d247" + }, + { + "key": "Cache-Control", + "value": "no-cache, no-store, max-age=0, must-revalidate" + }, + { + "key": "Content-Security-Policy", + "value": "default-src 'self' https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'; img-src 'self' https: data: blob:; style-src https: blob: 'unsafe-inline'; worker-src 'self' blob:; font-src 'self' https: data: blob:; child-src 'self' https: data: blob:;" + }, + { + "key": "Referrer-Policy", + "value": "no-referrer-when-downgrade" + }, + { + "key": "X-Content-Type-Options", + "value": "nosniff" + }, + { + "key": "X-Download-Options", + "value": "noopen" + }, + { + "key": "X-Frame-Options", + "value": "sameorigin" + }, + { + "key": "X-XSS-Protection", + "value": "1" + } + ], + "cookie": [], + "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"DEPARTMENT_ID\",\n \"message\": \"Department id doesn't exist in the system\",\n \"description\": null,\n \"params\": null\n },\n {\n \"code\": \"TENANT_ID\",\n \"message\": \"Tenant id doesn't exist in the system\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" + } + ] + }, + { + "name": "search_expenditure", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"910f4d23-fc63-48fb-a8fb-f0ad567b788a\",\"a4c21fc1-28df-494b-8983-baf3c6b027d7\"\n ],\n \"tenantId\": \"pb\"\n }\n}" + }, + "url": { + "raw": "https://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_search", + "protocol": "https", + "host": [ + "ifix-dev", + "ifix", + "org", + "in" + ], + "path": [ + "ifix-master-data", + "expenditure", + "v1", + "_search" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Project", + "item": [ + { + "name": "create_project", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Authorization", + "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzI0OTA2MjYsImlhdCI6MTYyOTg5ODYyNiwianRpIjoiNmNjOTZhOGYtMGUwZC00ZjE3LTg3YzUtYWJhMGQ4MDQwZWEwIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.dodHtCYpVQ5TU8hdbzLNwSA43hCj4QaD15iLjzgqdNpAKIHlbtWvlbxjD1AZZII-9mFgMknCLRMHnf4YGPQs06ACg-ClgEcpN0tIuOarnwRxlpc5CNNfWYUPI4Oqs9Dq-fnhOLF2asNVdgvtn5-oIbAbZMMf8cANBwa_Czo4sWCgQYivQxEjEq1vXczrF5vUGybsxrY53odYktu8XrALyoms8yCi6aO3g6lGLR9MvPfBK6ObUebDOUVtE0K6g8ukVrnNaNDz54EuCuYAg4tSJX0hevDQ09mWc-7vQOWf1MSoXmy98Z1NZqMPoLmftZbCLaJ-ZRO4cEYHEqOmvbDKfw" + }, + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"project\": {\n \"tenantId\": \"pb\",\n \"code\": \"DIV23\",\n \"name\": \"Sri Anandpur Sahib\",\n \"expenditureId\": \"910f4d23-fc63-48fb-a8fb-f0ad567b788a\",\n \"departmentEntitytId\": \"901f76a8-1911-4960-b389-57b62bd4dcdb\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/project/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "project", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "search_project", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac4\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ac5\"\n ],\n \"tenantId\": \"pb\",\n \"locationId\": \"2c8d44e8-cf2e-4974-97d7-f3ce848b543b\"\n }\n}" + }, + "url": { + "raw": "http://localhost:8030/ifix-master-data/project/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8030", + "path": [ + "ifix-master-data", + "project", + "v1", + "_search" + ] + } + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file From b7263dbdb3f58c410cb25c91cc9e4769c88bc68a Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Mon, 6 Sep 2021 12:51:17 +0530 Subject: [PATCH 32/67] Postman collection and API redocly link (#59) --- ...entEntityHierarchy.postman_collection.json | 164 ++++++++++++++++++ .../ifix-department-entity-service/README.md | 3 + 2 files changed, 167 insertions(+) create mode 100644 domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json diff --git a/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json b/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json new file mode 100644 index 00000000..a5cbd903 --- /dev/null +++ b/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json @@ -0,0 +1,164 @@ +{ + "info": { + "_postman_id": "270b3bfe-66ac-4b7d-b9d0-7bb16e5f872b", + "name": "DepartmentEntityHierarchy", + "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" + }, + "item": [ + { + "name": "Entity", + "item": [ + { + "name": "Department Entity Create", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [], + "body": { + "mode": "raw", + "raw": " {\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n }, \r\n \"departmentEntity\": {\r\n \"tenantId\": \"pb\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\r\n \"code\": \"KS\",\r\n \"name\": \"Kartarpur Sahib\",\r\n \"hierarchyLevel\": 3,\r\n \"children\": [\r\n \"7e3a29b4-8c26-4562-a882-2d0be1d2406a\", \"69c418a6-1bbf-4ef9-9bd2-bd26243d7c53\"\r\n ]\r\n }\r\n }", + "options": { + "raw": { + "language": "json" + } + } + }, + "url": { + "raw": "http://localhost:8032/ifix-department-entity/departmentEntity/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8032", + "path": [ + "ifix-department-entity", + "departmentEntity", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Department Entity Search", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"07fea07c-9ca9-4474-b6bc-c3a9456b181e\"\n ],\n \"tenantId\": \"pb\"\n }\n}" + }, + "url": { + "raw": "localhost:8032/ifix-department-entity/departmentEntity/v1/_search", + "host": [ + "localhost" + ], + "port": "8032", + "path": [ + "ifix-department-entity", + "departmentEntity", + "v1", + "_search" + ] + } + }, + "response": [] + } + ] + }, + { + "name": "Hierarchy", + "item": [ + { + "name": "Hierarchy Level Create", + "request": { + "auth": { + "type": "bearer", + "bearer": [ + { + "key": "token", + "value": "", + "type": "string" + } + ] + }, + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": " {\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n }\n }, \n \"departmentHierarchyLevel\": {\n \"tenantId\": \"pb\",\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\n \"label\": \"Department\",\n \"parent\":null\n }\n }" + }, + "url": { + "raw": "http://localhost:8032/ifix-department-entity-service/departmentEntity/hierarchyLevel/v1/_create", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8032", + "path": [ + "ifix-department-entity-service", + "departmentEntity", + "hierarchyLevel", + "v1", + "_create" + ] + } + }, + "response": [] + }, + { + "name": "Hierarchy Level Search", + "request": { + "method": "POST", + "header": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "body": { + "mode": "raw", + "raw": " {\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n }, \n \"criteria\": {\n \"Ids\": [\n \"5e648b1a-5f39-4995-9866-add56929848f\"\n ],\n \"tenantId\": \"pb\",\n \"level\": 0\n }\n }" + }, + "url": { + "raw": "http://localhost:8032/ifix-department-entity/departmentEntity/hierarchyLevel/v1/_search", + "protocol": "http", + "host": [ + "localhost" + ], + "port": "8032", + "path": [ + "ifix-department-entity", + "departmentEntity", + "hierarchyLevel", + "v1", + "_search" + ] + } + }, + "response": [] + } + ] + } + ] +} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/README.md b/domain-services/ifix-department-entity-service/README.md index 848d9d51..e5782fc5 100644 --- a/domain-services/ifix-department-entity-service/README.md +++ b/domain-services/ifix-department-entity-service/README.md @@ -1,5 +1,8 @@ # iFIX-Department-Entity-Service +## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml) + + ## Department Hierarchy It defines hierarchy definition for department. From 261767b90695aca33d15cb14746cf88e62633fae Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Mon, 6 Sep 2021 20:25:58 +0530 Subject: [PATCH 33/67] Ifix 386 (#60) --- .../DepartmentEntityRepository.java | 16 +++++++++ .../DepartmentHierarchyLevelRepository.java | 5 +++ .../DepartmentEntityQueryBuilder.java | 18 ++++++++++ .../DepartmentHierarchyLevelQueryBuilder.java | 11 ++++++ ...rtmentHierarchyLevelEnrichmentService.java | 4 +++ .../egov/util/DepartmentHierarchyUtil.java | 33 +++++++++++++++++ .../validator/DepartmentEntityValidator.java | 36 +++++++++++++++---- .../DepartmentHierarchyLevelValidator.java | 19 ++++++++++ 8 files changed, 136 insertions(+), 6 deletions(-) create mode 100644 domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentHierarchyUtil.java diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java index b99275f2..6bf298b6 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentEntityRepository.java @@ -12,6 +12,7 @@ import java.util.Collections; import java.util.List; +import java.util.Optional; @Repository public class DepartmentEntityRepository { @@ -45,4 +46,19 @@ public List searchEntity(DepartmentEntitySearchRequest departm } return Collections.emptyList(); } + + /** + * @param childIdList + * @param hierarchyLevel + * @return + */ + public List searchChildDepartment(List childIdList, Integer hierarchyLevel) { + Optional optionalQuery = queryBuilder.buildChildrenValidationQuery(childIdList, hierarchyLevel); + + if (optionalQuery.isPresent()) { + return mongoTemplate.find(optionalQuery.get(), DepartmentEntity.class); + } + + return Collections.emptyList(); + } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java index 68f8fe4f..f73fce7c 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/DepartmentHierarchyLevelRepository.java @@ -30,4 +30,9 @@ public List searchDeptHierarchyLevel(DepartmentHierarc Query searchQuery = queryBuilder.buildSearchQuery(searchCriteria); return (mongoTemplate.find(searchQuery, DepartmentHierarchyLevel.class)); } + + public List searchParentDeptHierarchyLevel(String departmentId, String tenantId, String parent) { + Query searchQuery = queryBuilder.buildParentDeptHierarchyLevelSearchQuery(departmentId,tenantId,parent); + return (mongoTemplate.find(searchQuery, DepartmentHierarchyLevel.class)); + } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java index eab52b32..b812ec14 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentEntityQueryBuilder.java @@ -7,6 +7,9 @@ import org.springframework.data.mongodb.core.query.Query; import org.springframework.stereotype.Component; +import java.util.List; +import java.util.Optional; + @Component @Slf4j public class DepartmentEntityQueryBuilder { @@ -32,4 +35,19 @@ public Query buildPlainSearchQuery(DepartmentEntitySearchCriteria searchCriteria return new Query(criteria); } + + /** + * @param childIdList + * @param hierarchyLevel + * @return + */ + public Optional buildChildrenValidationQuery(List childIdList, Integer hierarchyLevel) { + if (childIdList != null && !childIdList.isEmpty() && hierarchyLevel != null) { + hierarchyLevel += 1; + return Optional.ofNullable(new Query(Criteria.where("hierarchyLevel").is(hierarchyLevel) + .and("id").in(childIdList))); + } + + return Optional.empty(); + } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java index 2848647a..29068b9b 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/repository/queryBuilder/DepartmentHierarchyLevelQueryBuilder.java @@ -30,4 +30,15 @@ public Query buildSearchQuery(DepartmentHierarchyLevelSearchCriteria searchCrite return new Query(criteria); } + + public Query buildParentDeptHierarchyLevelSearchQuery(String departmentId, String tenantId, String parent) { + Criteria criteria = Criteria.where("tenantId").is(tenantId); + + if (StringUtils.isNotBlank(departmentId)) { + criteria.and("departmentId").is(departmentId); + } + criteria.and("parent").is(parent); + + return new Query(criteria); + } } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java index c9a2c15a..118b934b 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/service/DepartmentHierarchyLevelEnrichmentService.java @@ -44,6 +44,10 @@ public void enrichHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest reque auditDetails = departmentEntityUtil.enrichAuditDetails(requestHeader.getUserInfo().getUuid(), departmentHierarchyLevel.getAuditDetails(), false); } + if(StringUtils.isBlank(departmentHierarchyLevel.getParent())){ + departmentHierarchyLevel.setLevel(0); + departmentHierarchyLevel.setParent(null); + } enrichDepartmentLevel(departmentHierarchyLevel); departmentHierarchyLevel.setId(UUID.randomUUID().toString()); diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentHierarchyUtil.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentHierarchyUtil.java new file mode 100644 index 00000000..0656c594 --- /dev/null +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/util/DepartmentHierarchyUtil.java @@ -0,0 +1,33 @@ +package org.egov.util; + + +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.repository.DepartmentHierarchyLevelRepository; +import org.egov.web.models.DepartmentHierarchyLevel; +import org.egov.web.models.DepartmentHierarchyLevelSearchCriteria; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Collections; +import java.util.List; + +@Component +@Slf4j +public class DepartmentHierarchyUtil { + + @Autowired + private DepartmentHierarchyLevelRepository levelRepository; + + + public List validateHierarchyLevelMetaData(String departmentId, Integer hierarchyLevel, String tenantId) { + if (StringUtils.isNotBlank(departmentId) && StringUtils.isNotBlank(tenantId) && hierarchyLevel != null) { + DepartmentHierarchyLevelSearchCriteria searchCriteria = new DepartmentHierarchyLevelSearchCriteria(); + searchCriteria.setTenantId(tenantId); + searchCriteria.setDepartmentId(departmentId); + searchCriteria.setLevel(hierarchyLevel); + return (levelRepository.searchDeptHierarchyLevel(searchCriteria)); + } + return Collections.emptyList(); + } +} diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java index 5da358e8..f5fce1ff 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -2,13 +2,12 @@ import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.DepartmentEntityRepository; import org.egov.tracer.model.CustomException; import org.egov.util.DepartmentEntityConstant; +import org.egov.util.DepartmentHierarchyUtil; import org.egov.util.GovernmentUtil; -import org.egov.web.models.DepartmentEntity; -import org.egov.web.models.DepartmentEntityRequest; -import org.egov.web.models.DepartmentEntitySearchCriteria; -import org.egov.web.models.DepartmentEntitySearchRequest; +import org.egov.web.models.*; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @@ -22,8 +21,14 @@ public class DepartmentEntityValidator { @Autowired private GovernmentUtil governmentUtil; + @Autowired + DepartmentEntityRepository departmentEntityRepository; + + @Autowired + private DepartmentHierarchyUtil hierarchyUtil; + /** - * TODO: validation of HierarchyLevel and department id check. + * * Both combination should be checked in Department Hierarchy Level meta data. * * @param departmentEntityRequest @@ -81,11 +86,30 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (departmentEntity.getChildren() == null) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_CHILDREN, "Department children information is missing"); + }else { + List departmentEntityList = departmentEntityRepository + .searchChildDepartment(departmentEntity.getChildren(), departmentEntity.getHierarchyLevel()); + + if (departmentEntityList == null || departmentEntityList.isEmpty() + || (departmentEntityList.size() != departmentEntity.getChildren().size())) { + errorMap.put(DepartmentEntityConstant.DEPARTMENT_CHILDREN, "Invalid children id list"); + } } + if (!errorMap.isEmpty()) { throw new CustomException(errorMap); } - + if (StringUtils.isNotBlank(departmentEntity.getDepartmentId()) + && departmentEntity.getHierarchyLevel() != null + && StringUtils.isNotBlank(departmentEntity.getTenantId())) { + List departmentHierarchyLevels = hierarchyUtil.validateHierarchyLevelMetaData(departmentEntity.getDepartmentId() + , departmentEntity.getHierarchyLevel() + , departmentEntity.getTenantId()); + if (departmentHierarchyLevels == null || departmentHierarchyLevels.isEmpty()) { + errorMap.put(DepartmentEntityConstant.INVALID_HIERARCHY_LEVEL, "Given Hierarchy level of this department id : " + + departmentEntity.getDepartmentId() + " doesn't exist in the system."); + } + } } else { throw new CustomException(DepartmentEntityConstant.REQUEST_PAYLOAD_MISSING, "Request payload is missing some value"); } diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java index 13da16aa..a30e0062 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentHierarchyLevelValidator.java @@ -3,6 +3,7 @@ import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.egov.common.contract.request.RequestHeader; +import org.egov.repository.DepartmentHierarchyLevelRepository; import org.egov.tracer.model.CustomException; import org.egov.util.DepartmentEntityConstant; import org.egov.util.DepartmentUtil; @@ -28,6 +29,9 @@ public class DepartmentHierarchyLevelValidator { @Autowired private DepartmentUtil departmentUtil; + @Autowired + private DepartmentHierarchyLevelRepository levelRepository; + public void validateHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest request) { DepartmentHierarchyLevel departmentHierarchyLevel = request.getDepartmentHierarchyLevel(); RequestHeader requestHeader = request.getRequestHeader(); @@ -70,6 +74,21 @@ public void validateHierarchyLevelCreatePost(DepartmentHierarchyLevelRequest req + " doesn't exist in the system"); } + if(StringUtils.isNotBlank(departmentHierarchyLevel.getTenantId()) + && StringUtils.isNotBlank(departmentHierarchyLevel.getDepartmentId()) + && StringUtils.isBlank(departmentHierarchyLevel.getParent())) { + + List dbDepartmentHierarchyLevels = levelRepository.searchParentDeptHierarchyLevel( + departmentHierarchyLevel.getDepartmentId() + , departmentHierarchyLevel.getTenantId() + , departmentHierarchyLevel.getParent()); + if (dbDepartmentHierarchyLevels != null && !dbDepartmentHierarchyLevels.isEmpty()) { + errorMap.put(DepartmentEntityConstant.INVALID_DEPARTMENT_ID, "Department id : " + departmentHierarchyLevel.getDepartmentId() + + " is not valid for given parent"); + + } + } + if (!errorMap.isEmpty()) { throw new CustomException(errorMap); } From d00ea74a763c66c6f4c104d0161c6065fbc13fc2 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 7 Sep 2021 12:56:49 +0530 Subject: [PATCH 34/67] Add ps link (#61) --- .../fiscal-event-service/README.md | 1 + .../ifix-fiscal-event.postman_collection.json | 237 ---- ...entEntityHierarchy.postman_collection.json | 164 --- .../ifix-department-entity-service/README.md | 2 +- .../ifix-master-data-service/README.md | 1 + .../ifix-master-data.postman_collection.json | 1241 ----------------- 6 files changed, 3 insertions(+), 1643 deletions(-) delete mode 100644 domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json delete mode 100644 domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json delete mode 100644 domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json diff --git a/domain-services/fiscal-event-service/README.md b/domain-services/fiscal-event-service/README.md index dfdeb069..d9d48178 100644 --- a/domain-services/fiscal-event-service/README.md +++ b/domain-services/fiscal-event-service/README.md @@ -1,3 +1,4 @@ # Fiscal-Event-Service ## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/fiscal-event-service/fiscal-event-service-0.1.0.yaml) +## [Postman Collection Link](https://www.getpostman.com/collections/e9a94f8e896d8cfaa813) \ No newline at end of file diff --git a/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json b/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json deleted file mode 100644 index 7adb6dfd..00000000 --- a/domain-services/fiscal-event-service/ifix-fiscal-event.postman_collection.json +++ /dev/null @@ -1,237 +0,0 @@ -{ - "info": { - "_postman_id": "9d3c2923-ae2b-4010-b5fe-5e419e646748", - "name": "ifix-fiscal-event", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "fiscal-event-push", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"fiscalEvent\": {\r\n \"tenantId\": \"pb\",\r\n \"projectId\": \"69b1ed7c-c585-4731-b22d-469a26badeb9\",\r\n \"eventType\": \"Appropriation\",\r\n \"eventTime\": 1628177497000,\r\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\r\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\r\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\r\n \"amountDetails\": [\r\n {\r\n \"amount\": 10234.5,\r\n \"coaId\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\r\n \"fromBillingPeriod\": 1622907239000,\r\n \"toBillingPeriod\": 1628177643000\r\n }\r\n ],\r\n \"attributes\": {}\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8031/fiscal-event-service/events/v1/_push", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8031", - "path": [ - "fiscal-event-service", - "events", - "v1", - "_push" - ] - } - }, - "response": [] - }, - { - "name": "fiscal-event-push dev", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"fiscalEvent\": {\r\n \"tenantId\": \"pb\",\r\n \"projectId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac5\",\r\n \"eventType\": \"Bill\",\r\n \"eventTime\": 1629286294000,\r\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\r\n \"amountDetails\": [\r\n {\r\n \"amount\": 10234.5,\r\n \"coaId\": \"50cc5634-6cc3-456b-ae33-e40741128cde\",\r\n \"fromBillingPeriod\": 1622907239000,\r\n \"toBillingPeriod\": 1628177643000\r\n }\r\n ],\r\n \"attributes\": {}\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8031/fiscal-event-service/events/v1/_push", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8031", - "path": [ - "fiscal-event-service", - "events", - "v1", - "_push" - ] - } - }, - "response": [] - }, - { - "name": "fiscal-even-search", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"pb\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8031", - "path": [ - "fiscal-event-service", - "events", - "v1", - "_search" - ] - } - }, - "response": [ - { - "name": "fiscal-even-search", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"PB\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8031", - "path": [ - "fiscal-event-service", - "events", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Mon, 30 Aug 2021 08:43:47 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"fiscalEvent\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"tenantId\": \"PB\",\n \"projectId\": null,\n \"eventType\": \"APPROPRIATION\",\n \"ingestionTime\": null,\n \"eventTime\": 1628177497000,\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\n \"amountDetails\": [\n {\n \"id\": null,\n \"amount\": 10234.5,\n \"coaId\": null,\n \"fromBillingPeriod\": 1622907239000,\n \"toBillingPeriod\": 1628177643000\n }\n ],\n \"auditDetails\": null,\n \"attributes\": {}\n }\n ]\n}" - }, - { - "name": "fiscal-even-search", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"PB\",\r\n \"fromEventTime\": 1627776000000,\r\n \"toEventTime\": 1628985600000,\r\n \"eventType\":\"APPROPRIATION\"\r\n }\r\n \r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8031/fiscal-event-service/events/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8031", - "path": [ - "fiscal-event-service", - "events", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Tue, 31 Aug 2021 08:22:54 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"fiscalEvent\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"tenantId\": \"PB\",\n \"projectId\": \"69b1ed7c-c585-4731-b22d-469a26badeb9\",\n \"eventType\": \"APPROPRIATION\",\n \"ingestionTime\": null,\n \"eventTime\": 1628177497000,\n \"referenceId\": \"013e9c56-8207-4dac-9f4d-f1e20bd824e7\",\n \"parentEventId\": \"7d476bb0-bc9f-48e2-8ad4-5a4a36220779\",\n \"parentReferenceId\": \"77f23efe-879d-407b-8f23-7b8dd5b2ecb1\",\n \"amountDetails\": [\n {\n \"id\": \"612c9288f79ae7f62ed5863a\",\n \"amount\": 10234.5,\n \"coaId\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\n \"fromBillingPeriod\": 1622907239000,\n \"toBillingPeriod\": 1628177643000\n }\n ],\n \"auditDetails\": null,\n \"attributes\": {}\n }\n ]\n}" - } - ] - } - ] -} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json b/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json deleted file mode 100644 index a5cbd903..00000000 --- a/domain-services/ifix-department-entity-service/DepartmentEntityHierarchy.postman_collection.json +++ /dev/null @@ -1,164 +0,0 @@ -{ - "info": { - "_postman_id": "270b3bfe-66ac-4b7d-b9d0-7bb16e5f872b", - "name": "DepartmentEntityHierarchy", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Entity", - "item": [ - { - "name": "Department Entity Create", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": " {\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n }, \r\n \"departmentEntity\": {\r\n \"tenantId\": \"pb\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\r\n \"code\": \"KS\",\r\n \"name\": \"Kartarpur Sahib\",\r\n \"hierarchyLevel\": 3,\r\n \"children\": [\r\n \"7e3a29b4-8c26-4562-a882-2d0be1d2406a\", \"69c418a6-1bbf-4ef9-9bd2-bd26243d7c53\"\r\n ]\r\n }\r\n }", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8032/ifix-department-entity/departmentEntity/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8032", - "path": [ - "ifix-department-entity", - "departmentEntity", - "v1", - "_create" - ] - } - }, - "response": [] - }, - { - "name": "Department Entity Search", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"07fea07c-9ca9-4474-b6bc-c3a9456b181e\"\n ],\n \"tenantId\": \"pb\"\n }\n}" - }, - "url": { - "raw": "localhost:8032/ifix-department-entity/departmentEntity/v1/_search", - "host": [ - "localhost" - ], - "port": "8032", - "path": [ - "ifix-department-entity", - "departmentEntity", - "v1", - "_search" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Hierarchy", - "item": [ - { - "name": "Hierarchy Level Create", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": " {\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n }\n }, \n \"departmentHierarchyLevel\": {\n \"tenantId\": \"pb\",\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\n \"label\": \"Department\",\n \"parent\":null\n }\n }" - }, - "url": { - "raw": "http://localhost:8032/ifix-department-entity-service/departmentEntity/hierarchyLevel/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8032", - "path": [ - "ifix-department-entity-service", - "departmentEntity", - "hierarchyLevel", - "v1", - "_create" - ] - } - }, - "response": [] - }, - { - "name": "Hierarchy Level Search", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": " {\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n }, \n \"criteria\": {\n \"Ids\": [\n \"5e648b1a-5f39-4995-9866-add56929848f\"\n ],\n \"tenantId\": \"pb\",\n \"level\": 0\n }\n }" - }, - "url": { - "raw": "http://localhost:8032/ifix-department-entity/departmentEntity/hierarchyLevel/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8032", - "path": [ - "ifix-department-entity", - "departmentEntity", - "hierarchyLevel", - "v1", - "_search" - ] - } - }, - "response": [] - } - ] - } - ] -} \ No newline at end of file diff --git a/domain-services/ifix-department-entity-service/README.md b/domain-services/ifix-department-entity-service/README.md index e5782fc5..78f07433 100644 --- a/domain-services/ifix-department-entity-service/README.md +++ b/domain-services/ifix-department-entity-service/README.md @@ -1,7 +1,7 @@ # iFIX-Department-Entity-Service ## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/ifix-department-entity-service/ifix-department-entity-service-0.1.0.yaml) - +## [Postman Collection Link](https://www.getpostman.com/collections/b330dc3698bf009d2ef5) ## Department Hierarchy It defines hierarchy definition for department. diff --git a/domain-services/ifix-master-data-service/README.md b/domain-services/ifix-master-data-service/README.md index 9e509b06..620a9b5f 100644 --- a/domain-services/ifix-master-data-service/README.md +++ b/domain-services/ifix-master-data-service/README.md @@ -1,6 +1,7 @@ # iFIX-Master-Data-Service ## [API-Contract Link](https://redocly.github.io/redoc/?url=https://raw.githubusercontent.com/egovernments/iFix-Dev/develop/domain-services/ifix-master-data-service/ifix-master-data-service-0.1.0.yaml) +## [Postman Collection Link](https://www.getpostman.com/collections/6a3b9e0f07d03934725a) ## Connect to MongoDB through Playground pod Check the correct running mongodb pod and execute the below command diff --git a/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json b/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json deleted file mode 100644 index 64d03c02..00000000 --- a/domain-services/ifix-master-data-service/ifix-master-data.postman_collection.json +++ /dev/null @@ -1,1241 +0,0 @@ -{ - "info": { - "_postman_id": "fee8e3c9-0f45-46b3-967a-c8d0de45665e", - "name": "ifix-master-data", - "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json" - }, - "item": [ - { - "name": "Chart of account", - "item": [ - { - "name": "Create_COA", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"pb\",\r\n \"majorHead\": \"824\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"37\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://ifix-qa.ifix.org.in/ifix-master-data/chartOfAccount/v1/_create", - "protocol": "https", - "host": [ - "ifix-qa", - "ifix", - "org", - "in" - ], - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_create" - ] - } - }, - "response": [ - { - "name": "Create_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8988\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_create" - ] - } - }, - "status": "Accepted", - "code": 202, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Fri, 06 Aug 2021 08:51:00 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"a3bc991e-17db-4fb2-b015-8b29bdbb6a6a\",\n \"coaCode\": \"8988-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8988\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628239860279,\n \"lastModifiedTime\": 1628239860279\n }\n }\n ]\n}" - }, - { - "name": "Create_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8984\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_create" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Sat, 07 Aug 2021 07:01:56 GMT" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"DUPLICATE_COA_CODE\",\n \"message\": \"This coa code exists in the system\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" - }, - { - "name": "Create_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"chartOfAccount\": {\r\n \"tenantId\": \"PB\",\r\n \"majorHead\": \"8983\",\r\n \"majorHeadName\": \"majorHeadName89\",\r\n \"majorHeadtype\": \"majorHeadtype\",\r\n \"subMajorHead\": \"12\",\r\n \"subMajorHeadName\": \"subMajorHeadName\",\r\n \"minorHead\": \"347\",\r\n \"minorHeadName\": \"minorHeadName347\",\r\n \"subHead\": \"56\",\r\n \"subHeadName\": \"subHeadName\",\r\n \"groupHead\": \"78\",\r\n \"groupHeadName\": \"groupHeadName\",\r\n \"objectHead\": \"90\",\r\n \"objectHeadName\": \"objectHeadName\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_create" - ] - } - }, - "status": "Accepted", - "code": 202, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Sat, 07 Aug 2021 14:14:41 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"f064855d-d257-4737-bf52-cc48c4c7ff22\",\n \"coaCode\": \"8983-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8983\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadType\": null,\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628345681440,\n \"lastModifiedTime\": 1628345681440\n }\n }\n ]\n}" - } - ] - }, - { - "name": "Search_COA", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"9545d9a7-0d41-4f70-bb4d-c0c049776855\",\"512db21b-9d2b-4ae4-84d0-da1afe87db13\"\r\n ],\r\n \"tenantId\": \"pb\",\r\n \"subHead\": \"56\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "https://ifix-qa.ifix.org.in/ifix-master-data/chartOfAccount/v1/_search", - "protocol": "https", - "host": [ - "ifix-qa", - "ifix", - "org", - "in" - ], - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_search" - ] - } - }, - "response": [ - { - "name": "Search_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n\r\n \"tenantId\": \"string\",\r\n \"majorHead\": \"123\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 04 Aug 2021 08:15:36 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"20361abb-11ac-4b32-abe1-3abc7e6570db\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628064067597,\n \"lastModifiedTime\": 1628064067597\n }\n }\n ]\n}" - }, - { - "name": "Search_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"tenantId\": \"string\",\r\n \"majorHead\": \"123\",\r\n \"minorHead\": \"34\",\r\n \"subHead\": \"56\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 04 Aug 2021 08:17:21 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"20361abb-11ac-4b32-abe1-3abc7e6570db\",\n \"coaCode\": \"34-12-34-56-78-90-\",\n \"tenantId\": \"string\",\n \"majorHead\": \"123\",\n \"majorHeadName\": \"majorHeadName\",\n \"majorHeadtype\": \"majorHeadtype\",\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"34\",\n \"minorHeadName\": \"minorHeadName\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628064067597,\n \"lastModifiedTime\": 1628064067597\n }\n }\n ]\n}" - }, - { - "name": "Search_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \r\n \"majorHead\": \"123\",\r\n \"minorHead\": \"34\",\r\n \"subHead\": \"56\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_search" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 04 Aug 2021 08:22:43 GMT" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"ResponseInfo\": null,\n \"Errors\": [\n {\n \"code\": \"TENANT_ID\",\n \"message\": \"Tenant id is mandatory\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" - }, - { - "name": "Search_COA", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac0\",\"512db21b-9d2b-4ae4-84d0-da1afe87db13\"\r\n ],\r\n \"tenantId\": \"PB\",\r\n \"subHead\": \"56\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/chartOfAccount/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "chartOfAccount", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Sat, 07 Aug 2021 07:03:04 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"chartOfAccounts\": [\n {\n \"id\": \"512db21b-9d2b-4ae4-84d0-da1afe87db13\",\n \"coaCode\": \"8984-12-347-56-78-90\",\n \"tenantId\": \"PB\",\n \"majorHead\": \"8984\",\n \"majorHeadName\": \"majorHeadName89\",\n \"majorHeadType\": null,\n \"subMajorHead\": \"12\",\n \"subMajorHeadName\": \"subMajorHeadName\",\n \"minorHead\": \"347\",\n \"minorHeadName\": \"minorHeadName347\",\n \"subHead\": \"56\",\n \"subHeadName\": \"subHeadName\",\n \"groupHead\": \"78\",\n \"groupHeadName\": \"groupHeadName\",\n \"objectHead\": \"90\",\n \"objectHeadName\": \"objectHeadName\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628319687417,\n \"lastModifiedTime\": 1628319687417\n }\n }\n ]\n}" - } - ] - } - ] - }, - { - "name": "Government", - "item": [ - { - "name": "Create_Government", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"government\": {\r\n \"id\": \"pb\",\r\n \"name\": \"Punjab\",\r\n \"attributes\": {}\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/government/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "government", - "v1", - "_create" - ] - } - }, - "response": [ - { - "name": "Create_Government", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"government\": {\r\n \"id\": \"UP\",\r\n \"name\": \"Uttar Pardesh\",\r\n \"attributes\": {}\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/government/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "government", - "v1", - "_create" - ] - } - }, - "status": "Accepted", - "code": 202, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Sat, 07 Aug 2021 14:15:12 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"government\": [\n {\n \"id\": \"UP\",\n \"name\": \"Uttar Pardesh\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628345712790,\n \"lastModifiedTime\": 1628345712790\n },\n \"attributes\": {}\n }\n ]\n}" - } - ] - }, - { - "name": "Search_Government", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"pb\",\"br\",\"hr\",\"up\",\"ka\"\n ]\n }\n}" - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/government/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "government", - "v1", - "_search" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Department", - "item": [ - { - "name": "Search_Department", - "request": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ad3\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8020/ifix-master-data/department/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8020", - "path": [ - "ifix-master-data", - "department", - "v1", - "_search" - ] - } - }, - "response": [ - { - "name": "Search_Department", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data//department/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "", - "department", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Fri, 06 Aug 2021 08:20:56 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"department\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\n \"tenantId\": \"pb\",\n \"code\": \"123\",\n \"name\": \"departmentName\",\n \"isNodal\": false,\n \"parent\": \"parent\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n }\n ]\n}" - }, - { - "name": "Search_Department", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"criteria\": {\r\n \"Ids\": [\r\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ac2\"\r\n ],\r\n \"tenantId\": \"pb\"\r\n }\r\n}\r\n", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data//department/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "", - "department", - "v1", - "_search" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Fri, 06 Aug 2021 08:26:10 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseInfo\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"department\": [\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac1\",\n \"tenantId\": \"pb\",\n \"code\": \"123\",\n \"name\": \"departmentName\",\n \"isNodal\": false,\n \"parent\": \"parent\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n },\n {\n \"id\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ac2\",\n \"tenantId\": \"pb\",\n \"code\": \"1234\",\n \"name\": \"departmentName1\",\n \"isNodal\": false,\n \"parent\": \"parent1\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1628063909104,\n \"lastModifiedTime\": 1628063909104\n }\n }\n ]\n}" - } - ] - }, - { - "name": "create_department", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzI1NzUwNTEsImlhdCI6MTYyOTk4MzA1MSwianRpIjoiNmZkZTJiMjktY2VmZS00MDFjLWIwNjgtOWE0Y2ViYjM1YzdlIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.JsNvMIt8aQOiw2fnCtMN2a8xniBmH613cJu_MH_POjYL5nLI1ec4j7KA46gMxpKzy_2tL-LZ_snc4YtpertNdIOtoIk4KjH93DtKEnh2gAcuI_dbS4IRjBjyvqojkD0SJ6a3T17FwDLQk60TS9RytynhHQUjzeurC559bLhlTmEp1Q8Z0PtR5JnyjproHtoesVPoxCMq1Yuu5EBG2wcyKPlXnNXmGwt9WmdRaWPJFbhoEl0DxnuNDgBuP1nkB-mxA-nwPhNi90lLr1PUsdJ2xbkeQxekj4cUOf7bUn5ctJa1WcsNs2cjZeT5JJTMt_5FHSOjh1yr4cETN47pe0SrJQ" - }, - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"department\": {\n \"tenantId\": \"pb\",\n \"code\": \"DEP-1000\",\n \"name\": \"department-1000\",\n \"isNodal\": false,\n \"parent\": \"parent2\"\n }\n}" - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/department/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "department", - "v1", - "_create" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Expenditure", - "item": [ - { - "name": "Create_Expenditure", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"0.1.0\",\r\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"pb\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_create", - "protocol": "http", - "host": [ - "ifix-dev", - "ifix", - "org", - "in" - ], - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_create" - ] - } - }, - "response": [ - { - "name": "Create_Expenditure", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_create" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 01 Sep 2021 08:40:05 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"expenditure\": [\n {\n \"id\": \"dd3fe84b-f436-4b9d-88be-cfcbf23131f1\",\n \"tenantId\": \"PB\",\n \"code\": \"exp-01\",\n \"name\": \"expenditure one\",\n \"type\": \"Scheme\",\n \"departmentId\": null,\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1630485605296,\n \"lastModifiedTime\": 1630485605296\n }\n }\n ]\n}" - }, - { - "name": "Create_Expenditure", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_create" - ] - } - }, - "status": "OK", - "code": 200, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 01 Sep 2021 08:43:43 GMT" - }, - { - "key": "Keep-Alive", - "value": "timeout=60" - }, - { - "key": "Connection", - "value": "keep-alive" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": {\n \"ts\": 1627193067,\n \"correlationId\": null,\n \"msgId\": \"Unknown\",\n \"status\": \"successful\",\n \"signature\": \"NON\",\n \"version\": \"V1\"\n },\n \"expenditure\": [\n {\n \"id\": \"59bce7d2-9c87-4856-89cf-4a1f2ffba55a\",\n \"tenantId\": \"PB\",\n \"code\": \"exp-01\",\n \"name\": \"expenditure one\",\n \"type\": \"Scheme\",\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\",\n \"auditDetails\": {\n \"createdBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"lastModifiedBy\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\",\n \"createdTime\": 1630485823004,\n \"lastModifiedTime\": 1630485823004\n }\n }\n ]\n}" - }, - { - "name": "Create_Expenditure", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"PB\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/expenditure/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_create" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Date", - "value": "Wed, 01 Sep 2021 08:44:26 GMT" - }, - { - "key": "Connection", - "value": "close" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"EXPENDITURE_TYPE\",\n \"message\": \"Expenditure type is missing in request data\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" - }, - { - "name": "Create_Expenditure", - "originalRequest": { - "method": "POST", - "header": [], - "body": { - "mode": "raw", - "raw": "{\r\n \"requestHeader\": {\r\n \"ts\": 1627193067,\r\n \"version\": \"V1\",\r\n \"msgId\": \"Unknown\",\r\n \"signature\": \"NON\",\r\n \"userInfo\": {\r\n \"uuid\": \"e4fd96e8-3b6b-4e36-9503-0f14a01af39d\"\r\n }\r\n },\r\n \"expenditure\": {\r\n \"tenantId\": \"pb\",\r\n \"code\": \"exp-01\",\r\n \"name\": \"expenditure one\",\r\n \"type\": \"Scheme\",\r\n \"departmentId\": \"3d9ef18a-361a-40cf-b142-dd6f998e1ad2\"\r\n }\r\n}", - "options": { - "raw": { - "language": "json" - } - } - }, - "url": { - "raw": "http://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_create", - "protocol": "http", - "host": [ - "ifix-dev", - "ifix", - "org", - "in" - ], - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_create" - ] - } - }, - "status": "Bad Request", - "code": 400, - "_postman_previewlanguage": "json", - "header": [ - { - "key": "Date", - "value": "Thu, 02 Sep 2021 08:42:06 GMT" - }, - { - "key": "Content-Type", - "value": "application/json" - }, - { - "key": "Transfer-Encoding", - "value": "chunked" - }, - { - "key": "Connection", - "value": "keep-alive" - }, - { - "key": "Strict-Transport-Security", - "value": "max-age=63072000; includeSubdomains; preload" - }, - { - "key": "X-Lua-Resty-WAF-ID", - "value": "fb1470275dd9fd94e4eb" - }, - { - "key": "x-correlation-id", - "value": "c40f14a7-3951-4ba6-8795-47ce4ac3d247" - }, - { - "key": "Cache-Control", - "value": "no-cache, no-store, max-age=0, must-revalidate" - }, - { - "key": "Content-Security-Policy", - "value": "default-src 'self' https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'; img-src 'self' https: data: blob:; style-src https: blob: 'unsafe-inline'; worker-src 'self' blob:; font-src 'self' https: data: blob:; child-src 'self' https: data: blob:;" - }, - { - "key": "Referrer-Policy", - "value": "no-referrer-when-downgrade" - }, - { - "key": "X-Content-Type-Options", - "value": "nosniff" - }, - { - "key": "X-Download-Options", - "value": "noopen" - }, - { - "key": "X-Frame-Options", - "value": "sameorigin" - }, - { - "key": "X-XSS-Protection", - "value": "1" - } - ], - "cookie": [], - "body": "{\n \"responseHeader\": null,\n \"Errors\": [\n {\n \"code\": \"DEPARTMENT_ID\",\n \"message\": \"Department id doesn't exist in the system\",\n \"description\": null,\n \"params\": null\n },\n {\n \"code\": \"TENANT_ID\",\n \"message\": \"Tenant id doesn't exist in the system\",\n \"description\": null,\n \"params\": null\n }\n ]\n}" - } - ] - }, - { - "name": "search_expenditure", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"910f4d23-fc63-48fb-a8fb-f0ad567b788a\",\"a4c21fc1-28df-494b-8983-baf3c6b027d7\"\n ],\n \"tenantId\": \"pb\"\n }\n}" - }, - "url": { - "raw": "https://ifix-dev.ifix.org.in/ifix-master-data/expenditure/v1/_search", - "protocol": "https", - "host": [ - "ifix-dev", - "ifix", - "org", - "in" - ], - "path": [ - "ifix-master-data", - "expenditure", - "v1", - "_search" - ] - } - }, - "response": [] - } - ] - }, - { - "name": "Project", - "item": [ - { - "name": "create_project", - "request": { - "auth": { - "type": "bearer", - "bearer": [ - { - "key": "token", - "value": "", - "type": "string" - } - ] - }, - "method": "POST", - "header": [ - { - "key": "Authorization", - "value": "Bearer eyJhbGciOiJSUzI1NiIsInR5cCIgOiAiSldUIiwia2lkIiA6ICJPQUVaem05WEpRT0J0dkVHcTB4dklMeVBmbjlfUkVBUnBUUDNJY09hWjlvIn0.eyJleHAiOjE2MzI0OTA2MjYsImlhdCI6MTYyOTg5ODYyNiwianRpIjoiNmNjOTZhOGYtMGUwZC00ZjE3LTg3YzUtYWJhMGQ4MDQwZWEwIiwiaXNzIjoiaHR0cHM6Ly9pZml4LWRldi5pZml4Lm9yZy5pbi9hdXRoL3JlYWxtcy9pZml4IiwiYXVkIjoiYWNjb3VudCIsInN1YiI6IjRmYWE5MTJkLWQ1MzEtNDg1Yi1hZDliLTBhOTg3OGY3OTJiMCIsInR5cCI6IkJlYXJlciIsImF6cCI6Im1ncmFtc2V2YSIsImFjciI6IjEiLCJyZWFsbV9hY2Nlc3MiOnsicm9sZXMiOlsiZmlzY2FsLWV2ZW50LXByb2R1Y2VyIiwiZGVmYXVsdC1yb2xlcy1pZml4Il19LCJyZXNvdXJjZV9hY2Nlc3MiOnsiYWNjb3VudCI6eyJyb2xlcyI6WyJtYW5hZ2UtYWNjb3VudCIsIm1hbmFnZS1hY2NvdW50LWxpbmtzIiwidmlldy1wcm9maWxlIl19fSwic2NvcGUiOiJlbWFpbCBwcm9maWxlIiwiY2xpZW50SWQiOiJtZ3JhbXNldmEiLCJlbWFpbF92ZXJpZmllZCI6ZmFsc2UsInRlbmFudElkIjoicGIiLCJwcmVmZXJyZWRfdXNlcm5hbWUiOiJzZXJ2aWNlLWFjY291bnQtbWdyYW1zZXZhIn0.dodHtCYpVQ5TU8hdbzLNwSA43hCj4QaD15iLjzgqdNpAKIHlbtWvlbxjD1AZZII-9mFgMknCLRMHnf4YGPQs06ACg-ClgEcpN0tIuOarnwRxlpc5CNNfWYUPI4Oqs9Dq-fnhOLF2asNVdgvtn5-oIbAbZMMf8cANBwa_Czo4sWCgQYivQxEjEq1vXczrF5vUGybsxrY53odYktu8XrALyoms8yCi6aO3g6lGLR9MvPfBK6ObUebDOUVtE0K6g8ukVrnNaNDz54EuCuYAg4tSJX0hevDQ09mWc-7vQOWf1MSoXmy98Z1NZqMPoLmftZbCLaJ-ZRO4cEYHEqOmvbDKfw" - }, - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"project\": {\n \"tenantId\": \"pb\",\n \"code\": \"DIV23\",\n \"name\": \"Sri Anandpur Sahib\",\n \"expenditureId\": \"910f4d23-fc63-48fb-a8fb-f0ad567b788a\",\n \"departmentEntitytId\": \"901f76a8-1911-4960-b389-57b62bd4dcdb\"\n }\n}" - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/project/v1/_create", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "project", - "v1", - "_create" - ] - } - }, - "response": [] - }, - { - "name": "search_project", - "request": { - "method": "POST", - "header": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "body": { - "mode": "raw", - "raw": "{\n \"requestHeader\": {\n \"ts\": 1627193067,\n \"version\": \"0.1.0\",\n \"msgId\": \"ek9d96e8-3b6b-4e36-9503-0f14a01af74n\"\n },\n \"criteria\": {\n \"Ids\": [\n \"3d9ef18a-361a-40cf-b142-dd6f998e1ac4\",\"3d9ef18a-361a-40cf-b142-dd6f998e1ac5\"\n ],\n \"tenantId\": \"pb\",\n \"locationId\": \"2c8d44e8-cf2e-4974-97d7-f3ce848b543b\"\n }\n}" - }, - "url": { - "raw": "http://localhost:8030/ifix-master-data/project/v1/_search", - "protocol": "http", - "host": [ - "localhost" - ], - "port": "8030", - "path": [ - "ifix-master-data", - "project", - "v1", - "_search" - ] - } - }, - "response": [] - } - ] - } - ] -} \ No newline at end of file From 8ee00d24d06a7fb408cd9e86df1bb1eaa75413e3 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 7 Sep 2021 14:38:36 +0530 Subject: [PATCH 35/67] Bug fix regarding refactor (#62) --- .../egov/repository/queryBuilder/ProjectQueryBuilder.java | 6 +++--- .../src/main/java/org/egov/validator/ProjectValidator.java | 6 +++--- .../java/org/egov/web/models/ProjectSearchCriteria.java | 4 ++-- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java index 0a2645c3..c41cd3d4 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/repository/queryBuilder/ProjectQueryBuilder.java @@ -27,11 +27,11 @@ public Query buildQuerySearch(ProjectSearchCriteria projectSearchCriteria) { } if (!StringUtils.isEmpty(projectSearchCriteria.getExpenditureId())) { - criteria.and("eatId").is(projectSearchCriteria.getExpenditureId()); + criteria.and("expenditureId").is(projectSearchCriteria.getExpenditureId()); } - if (!StringUtils.isEmpty(projectSearchCriteria.getDepartmentId())) { - criteria.and("departmentId").is(projectSearchCriteria.getDepartmentId()); + if (!StringUtils.isEmpty(projectSearchCriteria.getGetDepartmentEntitytId())) { + criteria.and("departmentEntitytId").is(projectSearchCriteria.getGetDepartmentEntitytId()); } if (projectSearchCriteria.getIds() != null && !projectSearchCriteria.getIds().isEmpty()) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java index 6a36c6b4..9d8c331b 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/validator/ProjectValidator.java @@ -75,9 +75,9 @@ public void validateProjectSearchRequest(ProjectSearchRequest projectSearchReque "Length range [2-64]"); } - if (!StringUtils.isEmpty(projectSearchCriteria.getDepartmentId()) - && (projectSearchCriteria.getDepartmentId().length() < 2 - || projectSearchCriteria.getDepartmentId().length() > 64)) { + if (!StringUtils.isEmpty(projectSearchCriteria.getGetDepartmentEntitytId()) + && (projectSearchCriteria.getGetDepartmentEntitytId().length() < 2 + || projectSearchCriteria.getGetDepartmentEntitytId().length() > 64)) { throw new CustomException(MasterDataConstants.DEPARTMENT_ID, "Department id length is invalid. " + "Length range [2-64]"); diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java index 8addc77a..acda9ab5 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/web/models/ProjectSearchCriteria.java @@ -38,8 +38,8 @@ public class ProjectSearchCriteria { @JsonProperty("expenditureId") private String expenditureId = null; - @JsonProperty("departmentId") - private String departmentId = null; + @JsonProperty("departmentEntitytId") + private String getDepartmentEntitytId = null; @JsonProperty("locationId") private String locationId = null; From 566fdfe7d742372eb564886e157a7f50863b688a Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Tue, 7 Sep 2021 15:42:31 +0530 Subject: [PATCH 36/67] Null check for corrupted project data (#63) Co-authored-by: pintu-eGov --- .../service/FiscalEventDereferenceService.java | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java index 05ebe830..4ba51621 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/service/FiscalEventDereferenceService.java @@ -112,11 +112,14 @@ private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalE String expenditureId = null; String departmentId = null; if (projectNode != null && !projectNode.isEmpty()) { - expenditureId = projectNode.get("expenditureId").asText(); - departmentId = projectNode.get("departmentEntity").get("departmentId").asText(); + expenditureId = projectNode.get("expenditureId") != null ? projectNode.get("expenditureId").asText() : null; + departmentId = projectNode.get("departmentEntity") != null && projectNode.get("departmentEntity").get("departmentId") != null + ? projectNode.get("departmentEntity").get("departmentId").asText() : null; fiscalEventDeReferenced.setProject(getProjectDetails(projectNode)); - fiscalEventDeReferenced.setDepartmentEntity(projectUtil.getDepartmentEntityFromProject(projectNode.get("departmentEntity"))); + if (projectNode.get("departmentEntity") != null) { + fiscalEventDeReferenced.setDepartmentEntity(projectUtil.getDepartmentEntityFromProject(projectNode.get("departmentEntity"))); + } } List expenditureList = null; @@ -144,9 +147,9 @@ private void dereferenceProjectId(FiscalEventRequest fiscalEventRequest, FiscalE } private Project getProjectDetails(JsonNode projectNode) { - return Project.builder().id(projectNode.get("id").asText()) - .code(projectNode.get("code").asText()) - .name(projectNode.get("name").asText()).build(); + return Project.builder().id(projectNode.get("id") != null ? projectNode.get("id").asText() : null) + .code(projectNode.get("code") != null ? projectNode.get("code").asText() : null) + .name(projectNode.get("name") != null ? projectNode.get("name").asText() : null).build(); } /** From 3c10113be35f508fc9298c1e2ff1636d82ad57a0 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 7 Sep 2021 18:00:13 +0530 Subject: [PATCH 37/67] Department Entity check at fiscal event push (#64) --- .../org/egov/util/MasterDataConstants.java | 4 ++++ .../main/java/org/egov/util/ProjectUtil.java | 24 ++++++++----------- .../egov/validator/FiscalEventValidator.java | 23 ++++++++++++++++-- 3 files changed, 35 insertions(+), 16 deletions(-) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java index 3a444982..4a221bfa 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/MasterDataConstants.java @@ -31,5 +31,9 @@ private MasterDataConstants() { public static final String SEARCH_CRITERIA = "SEARCH_CRITERIA"; + public static final String PROJECT_ID_EXPENDITURE_ID = "PROJECT_ID-EXPENDITURE_ID"; + public static final String PROJECT_ID_DEPARTMENT_ENTITY_ID = "PROJECT_ID-EXPENDITURE_ID"; + + } diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java index 9119b3e1..034b1d0a 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/util/ProjectUtil.java @@ -1,5 +1,7 @@ package org.egov.util; +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import com.jayway.jsonpath.JsonPath; import org.apache.commons.lang3.StringUtils; import org.egov.config.FiscalEventConfiguration; @@ -9,10 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; @Component public class ProjectUtil { @@ -22,11 +21,14 @@ public class ProjectUtil { @Autowired ServiceRequestRepository serviceRequestRepository; + @Autowired + ObjectMapper objectMapper; + /** * @param fiscalEventRequest * @return */ - public boolean validateProjectId(FiscalEventRequest fiscalEventRequest) { + public Optional validateProjectId(FiscalEventRequest fiscalEventRequest) { if (fiscalEventRequest != null && fiscalEventRequest.getRequestHeader() != null && fiscalEventRequest.getFiscalEvent() != null && !StringUtils.isEmpty(fiscalEventRequest.getFiscalEvent().getProjectId())) { @@ -42,16 +44,10 @@ public boolean validateProjectId(FiscalEventRequest fiscalEventRequest) { ProjectMap.put(MasterDataConstants.CRITERIA, projectValueMap); Object response = serviceRequestRepository.fetchResult(createSearchProjectUrl(), ProjectMap); - - try { - List list = JsonPath.read(response, MasterDataConstants.PROJECT_LIST); - - return list != null && !list.isEmpty(); - } catch (Exception e) { - throw new CustomException(MasterDataConstants.JSONPATH_ERROR, "Failed to parse project response for projectId"); - } + JsonNode jsonNode = objectMapper.convertValue(response, JsonNode.class); + return Optional.ofNullable(jsonNode); } - return false; + return Optional.empty(); } private String createSearchProjectUrl() { diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index d3c05008..026dc0cb 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -1,6 +1,7 @@ package org.egov.validator; +import com.fasterxml.jackson.databind.JsonNode; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.EnumUtils; import org.apache.commons.lang3.StringUtils; @@ -157,10 +158,28 @@ public void validateTenantId(FiscalEventRequest fiscalEventRequest, Map errorMap) { - boolean isValidProject = projectUtil.validateProjectId(fiscalEventRequest); + Optional optionalJsonNode = projectUtil.validateProjectId(fiscalEventRequest); - if (!isValidProject) { + if (!optionalJsonNode.isPresent()) { errorMap.put(MasterDataConstants.PROJECT_ID, "Project id doesn't exist in the system"); + }else { + JsonNode jsonNode = optionalJsonNode.get(); + JsonNode projectListNode = jsonNode.get("project"); + + if (projectListNode != null && !projectListNode.isEmpty()) { + JsonNode projectNode = projectListNode.get(0); + + if (projectNode.get("expenditureId") == null) { + errorMap.put(MasterDataConstants.PROJECT_ID_EXPENDITURE_ID, "Expenditure details is missing in project"); + } + + if (projectNode.get("departmentEntity") == null + || projectNode.get("departmentEntity").get("departmentId") == null) { + errorMap.put(MasterDataConstants.PROJECT_ID_DEPARTMENT_ENTITY_ID, "Department entity details doesn't exist in the project"); + } + } else { + errorMap.put(MasterDataConstants.PROJECT_ID, "Project doesn't exist in the system"); + } } } From a4a62cd8eb8f27fbcc737707fc253b7b7cac58c6 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Tue, 7 Sep 2021 18:06:14 +0530 Subject: [PATCH 38/67] Bug fix department entity check while fetching from department entity service (#65) --- .../ProjectDepartmentEntityIntegration.java | 30 ++++++++++++------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java index 831ca739..06ef7dd0 100644 --- a/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java +++ b/domain-services/ifix-master-data-service/src/main/java/org/egov/service/ProjectDepartmentEntityIntegration.java @@ -8,6 +8,8 @@ import org.egov.common.contract.request.RequestHeader; import org.egov.config.MasterDataServiceConfiguration; import org.egov.repository.ServiceRequestRepository; +import org.egov.tracer.model.CustomException; +import org.egov.util.MasterDataConstants; import org.egov.web.models.DepartmentEntity; import org.egov.web.models.DepartmentEntityAttributes; import org.springframework.beans.factory.annotation.Autowired; @@ -61,17 +63,25 @@ private JsonNode createDepartmentEntitySearchRequest(RequestHeader requestHeader } private DepartmentEntity getCurrentDepartmentEntity(JsonNode departmentEntityDetails) { - while (departmentEntityDetails.get("children").size() != 0) { - departmentEntityDetails = departmentEntityDetails.get("children").get(0); + if (departmentEntityDetails != null) { + while (departmentEntityDetails.get("children").size() != 0) { + departmentEntityDetails = departmentEntityDetails.get("children").get(0); + } + DepartmentEntity departmentEntity = DepartmentEntity.builder() + .id(departmentEntityDetails.get("id") != null ? departmentEntityDetails.get("id").asText() : null) + .code(departmentEntityDetails.get("code") != null + ? departmentEntityDetails.get("code").asText() : null) + .name(departmentEntityDetails.get("name") != null + ? departmentEntityDetails.get("name").asText() : null) + .hierarchyLevel(departmentEntityDetails.get("hierarchyLevel") != null + ? departmentEntityDetails.get("hierarchyLevel").asInt() : null) + .departmentId(departmentEntityDetails.get("departmentId") != null + ? departmentEntityDetails.get("departmentId").asText() : null) + .build(); + return departmentEntity; + } else { + throw new CustomException(MasterDataConstants.DEPARTMENT_ENTITY_ID, "Department entity details are missing"); } - DepartmentEntity departmentEntity = DepartmentEntity.builder() - .id(departmentEntityDetails.get("id").asText()) - .code(departmentEntityDetails.get("code").asText()) - .name(departmentEntityDetails.get("name").asText()) - .hierarchyLevel(departmentEntityDetails.get("hierarchyLevel").asInt()) - .departmentId(departmentEntityDetails.get("departmentId").asText()) - .build(); - return departmentEntity; } private List createAncestryArrayFor(JsonNode departmentEntityDetails) { From 6c3858103a2b4ddece674c05b86ff08b6ffc9cb7 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Wed, 8 Sep 2021 13:51:46 +0530 Subject: [PATCH 39/67] Kafka consumer lag issue (#67) --- .../java/org/egov/consumer/FiscalEventDereferenceConsumer.java | 1 + .../org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java | 1 + 2 files changed, 2 insertions(+) diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java index b81ff40e..8795fcec 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventDereferenceConsumer.java @@ -41,6 +41,7 @@ public void listen(final HashMap record, @Header(KafkaHeaders.RE producer.push(processorConfig.getFiscalEventDereferenceTopic(), fiscalEventDeReferenced); } catch (Exception e) { log.error("Error occurred while processing the record from topic : " + topic, e); + throw new RuntimeException(e); } } } diff --git a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java index 2fd8f2fa..82553ae1 100644 --- a/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java +++ b/domain-services/fiscal-event-post-processor/src/main/java/org/egov/consumer/FiscalEventUnbundledFlattenConsumer.java @@ -54,6 +54,7 @@ public void listen(final HashMap record, @Header(KafkaHeaders.RE } } catch (Exception e) { log.error("Error occurred while processing the record from topic : " + topic, e); + throw new RuntimeException(e); } } } From 14ba7c12056b54210655c69a6862843d219bcb46 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 8 Sep 2021 17:56:03 +0530 Subject: [PATCH 40/67] Department entity children fix (#69) --- .../main/java/org/egov/validator/DepartmentEntityValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java index f5fce1ff..1411ee40 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -86,7 +86,7 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (departmentEntity.getChildren() == null) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_CHILDREN, "Department children information is missing"); - }else { + }else if (!departmentEntity.getChildren().isEmpty()) { List departmentEntityList = departmentEntityRepository .searchChildDepartment(departmentEntity.getChildren(), departmentEntity.getHierarchyLevel()); From 3e585e7e8d053918706ac1a7a079500788122f41 Mon Sep 17 00:00:00 2001 From: rahu-eGov <87854667+rahu-eGov@users.noreply.github.com> Date: Wed, 8 Sep 2021 23:11:31 +0530 Subject: [PATCH 41/67] Hierarchy level zero addition (#70) --- .../java/org/egov/validator/DepartmentEntityValidator.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java index 1411ee40..5d6cb999 100644 --- a/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java +++ b/domain-services/ifix-department-entity-service/src/main/java/org/egov/validator/DepartmentEntityValidator.java @@ -79,9 +79,6 @@ public void validateDepartmentEntityRequest(DepartmentEntityRequest departmentEn if (departmentEntity.getHierarchyLevel() == null) { errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id" + " is missing in request data"); - } else if (departmentEntity.getHierarchyLevel() < 1 || departmentEntity.getHierarchyLevel() > 256) { - errorMap.put(DepartmentEntityConstant.DEPARTMENT_HIERARCHY_ID, "Department hierarchy id " + - "length is invalid. Length range [2-256]"); } if (departmentEntity.getChildren() == null) { From 99f59019be10f255dfdf5ac08e5eeeaf6d6411eb Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 9 Sep 2021 13:56:25 +0530 Subject: [PATCH 42/67] Corrected collection name of fiscal event (#72) --- .../main/java/org/egov/repository/FiscalEventRepository.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java index 063b15e2..2bd14d34 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/repository/FiscalEventRepository.java @@ -23,6 +23,6 @@ public class FiscalEventRepository { public List searchFiscalEvent(Criteria searchCriteria) { Query searchQuery = eventQueryBuilder.buildSearchQuery(searchCriteria); - return (mongoTemplate.find(searchQuery, Object.class, "fiscalEvent")); + return (mongoTemplate.find(searchQuery, Object.class, "fiscal_event")); } } From 10e681a9af4555310be80c60f0fba37f96a69f73 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 9 Sep 2021 14:19:13 +0530 Subject: [PATCH 43/67] Updated the readme doc (#71) * Updated the readme doc * Updated the readme doc Co-authored-by: pintu-eGov --- .../ifix-department-entity-service/README.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/domain-services/ifix-department-entity-service/README.md b/domain-services/ifix-department-entity-service/README.md index 78f07433..423ce355 100644 --- a/domain-services/ifix-department-entity-service/README.md +++ b/domain-services/ifix-department-entity-service/README.md @@ -27,5 +27,22 @@ Children list contains department entity id list, which makes current department 1. First we need to define the hierarchy level top to bottom because it has parent's reference. 2. Only then we can start adding department entities, bottom-to-top because it has child's reference. -_**Note**: The root department hierarchy will have the label "Department", and the root department entity will be the +_**Note**: +1. The root department hierarchy will have the label "Department", and the root department entity will be the department itself._ +2. When we have to update the existing children list of Department Entity then update the existing children list using mongodb command like below: + + **Steps**: + + 1. Find the department entity parent where the new children need to be added. Do search by name and hierarchy level. + + db.departmentEntity.find({"name" : "","hierarchyLevel": }); + + 2. Append the department entity id at the end of the current department entity children's list. So first find the length of the current array and then set it as + "children.n": "" (where n is the length of the array.). + + e.g: + db.departmentEntity.update({"_id": ""},{$set: + {"children.n": "", + "children.n+1": ""} + }) \ No newline at end of file From 89f2702c46ba48f1d35da3402825ceabe1c5759c Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 9 Sep 2021 15:15:43 +0530 Subject: [PATCH 44/67] Corrected collection name (#73) * Corrected collection name of fiscal event * fiscal event amount details Co-authored-by: pintu-eGov --- .../src/main/java/org/egov/validator/FiscalEventValidator.java | 1 + 1 file changed, 1 insertion(+) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index 026dc0cb..83a09960 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -61,6 +61,7 @@ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { validateProjectId(fiscalEventRequest, errorMap); validateFiscalEventAmountDetails(fiscalEventRequest, errorMap); validateParentEventId(fiscalEventRequest, errorMap); + validateFiscalEventAmountDetails(fiscalEventRequest,errorMap); if (!errorMap.isEmpty()) { throw new CustomException(errorMap); From 0864eba6dc56b9b49f1ef1232e44d7dd778782b8 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 9 Sep 2021 15:24:03 +0530 Subject: [PATCH 45/67] Update FiscalEventValidator.java (#74) Removed the duplicate call of validate amount details --- .../src/main/java/org/egov/validator/FiscalEventValidator.java | 1 - 1 file changed, 1 deletion(-) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index 83a09960..026dc0cb 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -61,7 +61,6 @@ public void validateFiscalEventPushPost(FiscalEventRequest fiscalEventRequest) { validateProjectId(fiscalEventRequest, errorMap); validateFiscalEventAmountDetails(fiscalEventRequest, errorMap); validateParentEventId(fiscalEventRequest, errorMap); - validateFiscalEventAmountDetails(fiscalEventRequest,errorMap); if (!errorMap.isEmpty()) { throw new CustomException(errorMap); From 2bdf8d047cdfd0b1d865d28e3485476d432c6bd2 Mon Sep 17 00:00:00 2001 From: pintu-eGov <87848739+pintu-eGov@users.noreply.github.com> Date: Thu, 9 Sep 2021 15:43:46 +0530 Subject: [PATCH 46/67] CoaId null fix (#75) Co-authored-by: pintu-eGov --- .../src/main/java/org/egov/validator/FiscalEventValidator.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java index 026dc0cb..1465f83b 100644 --- a/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java +++ b/domain-services/fiscal-event-service/src/main/java/org/egov/validator/FiscalEventValidator.java @@ -122,6 +122,8 @@ private void validateFiscalEventAmountDetails(FiscalEventRequest fiscalEventRequ errorMap.put("AMOUNT-" + index++, "Amount is missing for coaId : " + amount.getCoaId()); if (StringUtils.isNotBlank(amount.getCoaId())) coaIds.add(amount.getCoaId()); + else + throw new CustomException("COA_ID","COA id is missing in the request data"); } List responseCoaIds = coaUtil.getCOAIdsFromCOAService(requestHeader, fiscalEventRequest.getFiscalEvent()); From cad83fbde13ad1006e80ca095b61fdd3ce9573da Mon Sep 17 00:00:00 2001 From: nikesh-eGov Date: Wed, 15 Sep 2021 14:50:23 +0530 Subject: [PATCH 47/67] Added utilities --- CODEOWNERS | 1 + utilities/README.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 utilities/README.md diff --git a/CODEOWNERS b/CODEOWNERS index 09d8a63f..009db1c2 100644 --- a/CODEOWNERS +++ b/CODEOWNERS @@ -2,3 +2,4 @@ core/ @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov reference-adapter/ @manikanta-pt-eGov @sathishp-eGov @GhanshyamRawat-eGov domain-services/ @sathishp-eGov @rushang7-eGov @GhanshyamRawat-eGov +utilities/ @sathishp-eGov @rushang7-eGov diff --git a/utilities/README.md b/utilities/README.md new file mode 100644 index 00000000..26404bf5 --- /dev/null +++ b/utilities/README.md @@ -0,0 +1 @@ +utilities From 1dd5b9511ea8c0017016f82dce1190a8dd9eb4e9 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Wed, 15 Sep 2021 18:04:31 +0530 Subject: [PATCH 48/67] initial aggregate setup --- .../.gitignore | 33 ++ .../.mvn/wrapper/MavenWrapperDownloader.java | 117 +++++++ .../.mvn/wrapper/maven-wrapper.jar | Bin 0 -> 50710 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 + .../fiscal-event-aggregator-service/mvnw | 310 ++++++++++++++++++ .../fiscal-event-aggregator-service/mvnw.cmd | 182 ++++++++++ .../fiscal-event-aggregator-service/pom.xml | 68 ++++ ...scalEventAggregatorServiceApplication.java | 15 + .../config/ConfigProperties.java | 28 ++ .../config/FiscalEventConfiguration.java | 59 ++++ .../processor/DruidDataQueryProcessor.java | 92 ++++++ .../FiscalEventAggregateProcessor.java | 20 ++ .../src/main/resources/application.properties | 8 + ...20210914173000__fiscal_event_aggregate.sql | 83 +++++ ...ventAggregatorServiceApplicationTests.java | 13 + 15 files changed, 1030 insertions(+) create mode 100644 reference-dashboard/fiscal-event-aggregator-service/.gitignore create mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar create mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties create mode 100644 reference-dashboard/fiscal-event-aggregator-service/mvnw create mode 100644 reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd create mode 100644 reference-dashboard/fiscal-event-aggregator-service/pom.xml create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql create mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java diff --git a/reference-dashboard/fiscal-event-aggregator-service/.gitignore b/reference-dashboard/fiscal-event-aggregator-service/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java new file mode 100644 index 00000000..e76d1f32 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java @@ -0,0 +1,117 @@ +/* + * Copyright 2007-present the original author or authors. + * + * Licensed 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 + * + * https://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. + */ +import java.net.*; +import java.io.*; +import java.nio.channels.*; +import java.util.Properties; + +public class MavenWrapperDownloader { + + private static final String WRAPPER_VERSION = "0.5.6"; + /** + * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. + */ + private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" + + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; + + /** + * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to + * use instead of the default one. + */ + private static final String MAVEN_WRAPPER_PROPERTIES_PATH = + ".mvn/wrapper/maven-wrapper.properties"; + + /** + * Path where the maven-wrapper.jar will be saved to. + */ + private static final String MAVEN_WRAPPER_JAR_PATH = + ".mvn/wrapper/maven-wrapper.jar"; + + /** + * Name of the property which should be used to override the default download url for the wrapper. + */ + private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; + + public static void main(String args[]) { + System.out.println("- Downloader started"); + File baseDirectory = new File(args[0]); + System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); + + // If the maven-wrapper.properties exists, read it and check if it contains a custom + // wrapperUrl parameter. + File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); + String url = DEFAULT_DOWNLOAD_URL; + if(mavenWrapperPropertyFile.exists()) { + FileInputStream mavenWrapperPropertyFileInputStream = null; + try { + mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); + Properties mavenWrapperProperties = new Properties(); + mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); + url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); + } catch (IOException e) { + System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); + } finally { + try { + if(mavenWrapperPropertyFileInputStream != null) { + mavenWrapperPropertyFileInputStream.close(); + } + } catch (IOException e) { + // Ignore ... + } + } + } + System.out.println("- Downloading from: " + url); + + File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); + if(!outputFile.getParentFile().exists()) { + if(!outputFile.getParentFile().mkdirs()) { + System.out.println( + "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); + } + } + System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); + try { + downloadFileFromURL(url, outputFile); + System.out.println("Done"); + System.exit(0); + } catch (Throwable e) { + System.out.println("- Error downloading"); + e.printStackTrace(); + System.exit(1); + } + } + + private static void downloadFileFromURL(String urlString, File destination) throws Exception { + if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { + String username = System.getenv("MVNW_USERNAME"); + char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); + Authenticator.setDefault(new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(username, password); + } + }); + } + URL website = new URL(urlString); + ReadableByteChannel rbc; + rbc = Channels.newChannel(website.openStream()); + FileOutputStream fos = new FileOutputStream(destination); + fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); + fos.close(); + rbc.close(); + } + +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054 GIT binary patch literal 50710 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 EfAhh=DF6Tf literal 0 HcmV?d00001 diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties new file mode 100644 index 00000000..abd303b6 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties @@ -0,0 +1,2 @@ +distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip +wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/reference-dashboard/fiscal-event-aggregator-service/mvnw b/reference-dashboard/fiscal-event-aggregator-service/mvnw new file mode 100644 index 00000000..a16b5431 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/mvnw @@ -0,0 +1,310 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Maven Start Up Batch script +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# M2_HOME - location of maven2's installed home dir +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + export JAVA_HOME="`/usr/libexec/java_home`" + else + export JAVA_HOME="/Library/Java/Home" + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +if [ -z "$M2_HOME" ] ; then + ## resolve links - $0 may be a link to maven's home + PRG="$0" + + # need this for relative symlinks + while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG="`dirname "$PRG"`/$link" + fi + done + + saveddir=`pwd` + + M2_HOME=`dirname "$PRG"`/.. + + # make it fully qualified + M2_HOME=`cd "$M2_HOME" && pwd` + + cd "$saveddir" + # echo Using m2 at $M2_HOME +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --unix "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$M2_HOME" ] && + M2_HOME="`(cd "$M2_HOME"; pwd)`" + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`which java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + echo "${basedir}" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=`find_maven_basedir "$(pwd)"` +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + else + jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) jarUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $jarUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget "$jarUrl" -O "$wrapperJarPath" + else + wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" + fi + elif command -v curl > /dev/null; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl -o "$wrapperJarPath" "$jarUrl" -f + else + curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f + fi + + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaClass" ]; then + if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaClass") + fi + if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$M2_HOME" ] && + M2_HOME=`cygpath --path --windows "$M2_HOME"` + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd b/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd new file mode 100644 index 00000000..c8d43372 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd @@ -0,0 +1,182 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Maven Start Up Batch script +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM M2_HOME - location of maven2's installed home dir +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" +if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + +FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %DOWNLOAD_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" +if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%" == "on" pause + +if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% + +exit /B %ERROR_CODE% diff --git a/reference-dashboard/fiscal-event-aggregator-service/pom.xml b/reference-dashboard/fiscal-event-aggregator-service/pom.xml new file mode 100644 index 00000000..4edc5e81 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + org.egov + fiscal-event-aggregator-service + 0.0.1-SNAPSHOT + fiscal-event-aggregator-service + Aggregate the fiscal event post processed data + + 1.8 + + + + org.springframework.boot + spring-boot-starter + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + in.zapr.druid + druidry + 3.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java new file mode 100644 index 00000000..79a4e04b --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java @@ -0,0 +1,15 @@ +package org.egov.fiscaleventaggregatorservice; + +import lombok.Data; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@Data +public class FiscalEventAggregatorServiceApplication { + + public static void main(String[] args) { + SpringApplication.run(FiscalEventAggregatorServiceApplication.class, args); + } + +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java new file mode 100644 index 00000000..f48e0427 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java @@ -0,0 +1,28 @@ +package org.egov.fiscaleventaggregatorservice.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Data +public class ConfigProperties { + + @Value("${druid.host}") + private String druidHost; + + @Value("${druid.endPoint}") + private String druidEndPoint; + + @Value("${spring.datasource.driver-class-name}") + private String postgresDatasourceDriverClassName; + + @Value("${spring.datasource.url}") + private String postgresDatasourceUrl; + + @Value("${spring.datasource.username}") + private String postgresDatasourceUsername; + + @Value("${spring.datasource.password}") + private String postgresDatasourcePassword; +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java new file mode 100644 index 00000000..f915c44a --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java @@ -0,0 +1,59 @@ +package org.egov.fiscaleventaggregatorservice.config; + +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.DruidConfiguration; +import in.zapr.druid.druidry.client.DruidJerseyClient; +import in.zapr.druid.druidry.client.exception.ConnectionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import javax.sql.DataSource; + +@Configuration +public class FiscalEventConfiguration { + + @Autowired + private ConfigProperties configProperties; + + @Bean + public DruidClient getDruidClient() { + DruidConfiguration config = DruidConfiguration + .builder() + .host(configProperties.getDruidHost()) + .endpoint(configProperties.getDruidEndPoint()) + .build(); + + DruidClient client = new DruidJerseyClient(config); + try { + System.out.println("Druid Client : " + client); + client.connect(); + } catch (ConnectionException e) { + e.printStackTrace(); + } + //List responses = client.query(query, DruidResponse.class); +// try { +// client.close(); +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } + return client; + } + + public DataSource getDS() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(configProperties.getPostgresDatasourceDriverClassName()); + dataSource.setUrl(configProperties.getPostgresDatasourceUrl()); + dataSource.setUsername(configProperties.getPostgresDatasourceUsername()); + dataSource.setPassword(configProperties.getPostgresDatasourcePassword()); + return dataSource; + } + + + @Bean + public JdbcTemplate getJdbcTemplate() { + return new JdbcTemplate(getDS()); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java new file mode 100644 index 00000000..c0e33d71 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java @@ -0,0 +1,92 @@ +package org.egov.fiscaleventaggregatorservice.processor; + + +import in.zapr.druid.druidry.aggregator.DoubleSumAggregator; +import in.zapr.druid.druidry.aggregator.DruidAggregator; +import in.zapr.druid.druidry.aggregator.LongSumAggregator; +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.exception.QueryException; +import in.zapr.druid.druidry.dataSource.TableDataSource; +import in.zapr.druid.druidry.dimension.DruidDimension; +import in.zapr.druid.druidry.dimension.SimpleDimension; +import in.zapr.druid.druidry.granularity.Granularity; +import in.zapr.druid.druidry.granularity.PredefinedGranularity; +import in.zapr.druid.druidry.granularity.SimpleGranularity; +import in.zapr.druid.druidry.postAggregator.ArithmeticFunction; +import in.zapr.druid.druidry.postAggregator.ArithmeticPostAggregator; +import in.zapr.druid.druidry.postAggregator.DruidPostAggregator; +import in.zapr.druid.druidry.postAggregator.FieldAccessPostAggregator; +import in.zapr.druid.druidry.query.aggregation.DruidTopNQuery; +import in.zapr.druid.druidry.query.config.Interval; +import in.zapr.druid.druidry.topNMetric.SimpleMetric; +import in.zapr.druid.druidry.topNMetric.TopNMetric; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@Component +public class DruidDataQueryProcessor { + + @Autowired + private DruidClient druidClient; + + + //TODO + public void fetchFiscalEventFromDruid() { + System.out.println("*********** Druid_client : " + druidClient); + + TableDataSource dataSource = new TableDataSource("fiscal-event"); +// SelectorFilter selectorFilter1 = new SelectorFilter("dim1", "some_value"); +// SelectorFilter selectorFilter2 = new SelectorFilter("dim2", "some_other_val"); +// +// AndFilter filter = new AndFilter(Arrays.asList(selectorFilter1, selectorFilter2)); + + DruidAggregator aggregator1 = new LongSumAggregator("count", "count"); + DruidAggregator aggregator2 = new DoubleSumAggregator("some_metric", "some_metric"); + + FieldAccessPostAggregator fieldAccessPostAggregator1 + = new FieldAccessPostAggregator("some_metric", "some_metric"); + + FieldAccessPostAggregator fieldAccessPostAggregator2 + = new FieldAccessPostAggregator("count", "count"); + + DruidPostAggregator postAggregator = ArithmeticPostAggregator.builder() + .name("sample_divide") + .function(ArithmeticFunction.DIVIDE) + .fields(Arrays.asList(fieldAccessPostAggregator1, fieldAccessPostAggregator2)) + .build(); + + DateTime startTime = new DateTime(2013, 8, 31, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(2013, 9, 3, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + DruidDimension dimension = new SimpleDimension("sample_dim"); + TopNMetric metric = new SimpleMetric("count"); + + DruidTopNQuery query = DruidTopNQuery.builder() + .dataSource(dataSource) + .dimension(dimension) + .threshold(5) + .topNMetric(metric) + .granularity(granularity) + .filter(null) + .aggregators(Arrays.asList(aggregator1, aggregator2)) + .postAggregators(Collections.singletonList(postAggregator)) + .intervals(Collections.singletonList(interval)) + .build(); + + try { + List responses = druidClient.query(query, Object.class); + } catch (QueryException e) { + e.printStackTrace(); + } + + + } +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java new file mode 100644 index 00000000..8fac35b2 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java @@ -0,0 +1,20 @@ +package org.egov.fiscaleventaggregatorservice.processor; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class FiscalEventAggregateProcessor implements ApplicationRunner { + + @Autowired + private DruidDataQueryProcessor druidDataQueryProcessor; + + @Override + public void run(ApplicationArguments args) throws Exception { + druidDataQueryProcessor.fetchFiscalEventFromDruid(); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties new file mode 100644 index 00000000..63caf57d --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/fiscal_event +spring.datasource.username=postgres +spring.datasource.password=root + +## Druid Config ## +druid.host=https://druid-qa.ifix.org.in/ +druid.endPoint=druid/v2/ diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql new file mode 100644 index 00000000..0f4b16ce --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql @@ -0,0 +1,83 @@ +DROP TABLE IF EXISTS fiscal_event_aggregated; + +CREATE TABLE fiscal_event_aggregated( + ver TEXT, + id SERIAL, + tenantId TEXT, + government_id TEXT, + government_name TEXT, + eventType TEXT, + sumAmount DECIMAL, + fiscalPeriod TEXT, + count bigint, + department_id TEXT, + department_code TEXT, + department_name TEXT, + departmentEntity_ancestry_0_id TEXT, + departmentEntity_ancestry_0_code TEXT, + departmentEntity_ancestry_0_name TEXT, + departmentEntity_ancestry_0_hierarchyLevel integer, + departmentEntity_ancestry_1_id TEXT, + departmentEntity_ancestry_1_code TEXT, + departmentEntity_ancestry_1_name TEXT, + departmentEntity_ancestry_1_hierarchyLevel integer, + departmentEntity_ancestry_2_id TEXT, + departmentEntity_ancestry_2_code TEXT, + departmentEntity_ancestry_2_name TEXT, + departmentEntity_ancestry_2_hierarchyLevel integer, + departmentEntity_ancestry_3_id TEXT, + departmentEntity_ancestry_3_code TEXT, + departmentEntity_ancestry_3_name TEXT, + departmentEntity_ancestry_3_hierarchyLevel integer, + departmentEntity_ancestry_4_id TEXT, + departmentEntity_ancestry_4_code TEXT, + departmentEntity_ancestry_4_name TEXT, + departmentEntity_ancestry_4_hierarchyLevel integer, + departmentEntity_ancestry_5_id TEXT, + departmentEntity_ancestry_5_code TEXT, + departmentEntity_ancestry_5_name TEXT, + departmentEntity_ancestry_5_hierarchyLevel integer, + departmentEntity_ancestry_6_id TEXT, + departmentEntity_ancestry_6_code TEXT, + departmentEntity_ancestry_6_name TEXT, + departmentEntity_ancestry_6_hierarchyLevel integer, + departmentEntity_ancestry_7_id TEXT, + departmentEntity_ancestry_7_code TEXT, + departmentEntity_ancestry_7_name TEXT, + departmentEntity_ancestry_7_hierarchyLevel integer, + departmentEntity_ancestry_8_id TEXT, + departmentEntity_ancestry_8_code TEXT, + departmentEntity_ancestry_8_name TEXT, + departmentEntity_ancestry_8_hierarchyLevel integer, + departmentEntity_ancestry_9_id TEXT, + departmentEntity_ancestry_9_code TEXT, + departmentEntity_ancestry_9_name TEXT, + departmentEntity_ancestry_9_hierarchyLevel integer, + departmentEntity_ancestry_10_id TEXT, + departmentEntity_ancestry_10_code TEXT, + departmentEntity_ancestry_10_name TEXT, + departmentEntity_ancestry_10_hierarchyLevel integer, + expenditure_id TEXT, + expenditure_code TEXT, + expenditure_name TEXT, + expenditure_type TEXT, + project_id TEXT, + project_code TEXT, + project_name TEXT, + coa_id TEXT, + coa_coaCode TEXT, + coa_majorHead TEXT, + coa_majorHeadName TEXT, + coa_majorHeadType TEXT, + coa_subMajorHead TEXT, + coa_subMajorHeadName TEXT, + coa_minorHead TEXT, + coa_minorHeadName TEXT, + coa_subHead TEXT, + coa_subHeadName TEXT, + coa_groupHead TEXT, + coa_groupHeadName TEXT, + coa_objectHead TEXT, + coa_objectHeadName TEXT, + PRIMARY KEY (id) +); \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java b/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java new file mode 100644 index 00000000..a20d2ae4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java @@ -0,0 +1,13 @@ +package org.egov.fiscaleventaggregatorservice; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FiscalEventAggregatorServiceApplicationTests { + +// @Test +// void contextLoads() { +// } + +} From e2825c940da1b8b3d3e3f501dc1df58ab7e7bc2b Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Thu, 16 Sep 2021 10:51:54 +0530 Subject: [PATCH 49/67] Renamed the aggregator --- .../.gitignore | 33 -- .../.mvn/wrapper/MavenWrapperDownloader.java | 117 ------- .../.mvn/wrapper/maven-wrapper.jar | Bin 50710 -> 0 bytes .../.mvn/wrapper/maven-wrapper.properties | 2 - .../fiscal-event-aggregator-service/mvnw | 310 ------------------ .../fiscal-event-aggregator-service/mvnw.cmd | 182 ---------- .../fiscal-event-aggregator-service/pom.xml | 68 ---- ...scalEventAggregatorServiceApplication.java | 15 - .../config/ConfigProperties.java | 28 -- .../config/FiscalEventConfiguration.java | 59 ---- .../processor/DruidDataQueryProcessor.java | 92 ------ .../FiscalEventAggregateProcessor.java | 20 -- .../src/main/resources/application.properties | 8 - ...20210914173000__fiscal_event_aggregate.sql | 83 ----- ...ventAggregatorServiceApplicationTests.java | 13 - 15 files changed, 1030 deletions(-) delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/.gitignore delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/mvnw delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/pom.xml delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql delete mode 100644 reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java diff --git a/reference-dashboard/fiscal-event-aggregator-service/.gitignore b/reference-dashboard/fiscal-event-aggregator-service/.gitignore deleted file mode 100644 index 549e00a2..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -HELP.md -target/ -!.mvn/wrapper/maven-wrapper.jar -!**/src/main/**/target/ -!**/src/test/**/target/ - -### STS ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache - -### IntelliJ IDEA ### -.idea -*.iws -*.iml -*.ipr - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ -build/ -!**/src/main/**/build/ -!**/src/test/**/build/ - -### VS Code ### -.vscode/ diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java deleted file mode 100644 index e76d1f32..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/MavenWrapperDownloader.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright 2007-present the original author or authors. - * - * Licensed 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 - * - * https://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. - */ -import java.net.*; -import java.io.*; -import java.nio.channels.*; -import java.util.Properties; - -public class MavenWrapperDownloader { - - private static final String WRAPPER_VERSION = "0.5.6"; - /** - * Default URL to download the maven-wrapper.jar from, if no 'downloadUrl' is provided. - */ - private static final String DEFAULT_DOWNLOAD_URL = "https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/" - + WRAPPER_VERSION + "/maven-wrapper-" + WRAPPER_VERSION + ".jar"; - - /** - * Path to the maven-wrapper.properties file, which might contain a downloadUrl property to - * use instead of the default one. - */ - private static final String MAVEN_WRAPPER_PROPERTIES_PATH = - ".mvn/wrapper/maven-wrapper.properties"; - - /** - * Path where the maven-wrapper.jar will be saved to. - */ - private static final String MAVEN_WRAPPER_JAR_PATH = - ".mvn/wrapper/maven-wrapper.jar"; - - /** - * Name of the property which should be used to override the default download url for the wrapper. - */ - private static final String PROPERTY_NAME_WRAPPER_URL = "wrapperUrl"; - - public static void main(String args[]) { - System.out.println("- Downloader started"); - File baseDirectory = new File(args[0]); - System.out.println("- Using base directory: " + baseDirectory.getAbsolutePath()); - - // If the maven-wrapper.properties exists, read it and check if it contains a custom - // wrapperUrl parameter. - File mavenWrapperPropertyFile = new File(baseDirectory, MAVEN_WRAPPER_PROPERTIES_PATH); - String url = DEFAULT_DOWNLOAD_URL; - if(mavenWrapperPropertyFile.exists()) { - FileInputStream mavenWrapperPropertyFileInputStream = null; - try { - mavenWrapperPropertyFileInputStream = new FileInputStream(mavenWrapperPropertyFile); - Properties mavenWrapperProperties = new Properties(); - mavenWrapperProperties.load(mavenWrapperPropertyFileInputStream); - url = mavenWrapperProperties.getProperty(PROPERTY_NAME_WRAPPER_URL, url); - } catch (IOException e) { - System.out.println("- ERROR loading '" + MAVEN_WRAPPER_PROPERTIES_PATH + "'"); - } finally { - try { - if(mavenWrapperPropertyFileInputStream != null) { - mavenWrapperPropertyFileInputStream.close(); - } - } catch (IOException e) { - // Ignore ... - } - } - } - System.out.println("- Downloading from: " + url); - - File outputFile = new File(baseDirectory.getAbsolutePath(), MAVEN_WRAPPER_JAR_PATH); - if(!outputFile.getParentFile().exists()) { - if(!outputFile.getParentFile().mkdirs()) { - System.out.println( - "- ERROR creating output directory '" + outputFile.getParentFile().getAbsolutePath() + "'"); - } - } - System.out.println("- Downloading to: " + outputFile.getAbsolutePath()); - try { - downloadFileFromURL(url, outputFile); - System.out.println("Done"); - System.exit(0); - } catch (Throwable e) { - System.out.println("- Error downloading"); - e.printStackTrace(); - System.exit(1); - } - } - - private static void downloadFileFromURL(String urlString, File destination) throws Exception { - if (System.getenv("MVNW_USERNAME") != null && System.getenv("MVNW_PASSWORD") != null) { - String username = System.getenv("MVNW_USERNAME"); - char[] password = System.getenv("MVNW_PASSWORD").toCharArray(); - Authenticator.setDefault(new Authenticator() { - @Override - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication(username, password); - } - }); - } - URL website = new URL(urlString); - ReadableByteChannel rbc; - rbc = Channels.newChannel(website.openStream()); - FileOutputStream fos = new FileOutputStream(destination); - fos.getChannel().transferFrom(rbc, 0, Long.MAX_VALUE); - fos.close(); - rbc.close(); - } - -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.jar deleted file mode 100644 index 2cc7d4a55c0cd0092912bf49ae38b3a9e3fd0054..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 50710 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 EfAhh=DF6Tf diff --git a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties b/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties deleted file mode 100644 index abd303b6..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/.mvn/wrapper/maven-wrapper.properties +++ /dev/null @@ -1,2 +0,0 @@ -distributionUrl=https://repo.maven.apache.org/maven2/org/apache/maven/apache-maven/3.8.2/apache-maven-3.8.2-bin.zip -wrapperUrl=https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar diff --git a/reference-dashboard/fiscal-event-aggregator-service/mvnw b/reference-dashboard/fiscal-event-aggregator-service/mvnw deleted file mode 100644 index a16b5431..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/mvnw +++ /dev/null @@ -1,310 +0,0 @@ -#!/bin/sh -# ---------------------------------------------------------------------------- -# 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 -# -# https://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. -# ---------------------------------------------------------------------------- - -# ---------------------------------------------------------------------------- -# Maven Start Up Batch script -# -# Required ENV vars: -# ------------------ -# JAVA_HOME - location of a JDK home dir -# -# Optional ENV vars -# ----------------- -# M2_HOME - location of maven2's installed home dir -# MAVEN_OPTS - parameters passed to the Java VM when running Maven -# e.g. to debug Maven itself, use -# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -# MAVEN_SKIP_RC - flag to disable loading of mavenrc files -# ---------------------------------------------------------------------------- - -if [ -z "$MAVEN_SKIP_RC" ] ; then - - if [ -f /etc/mavenrc ] ; then - . /etc/mavenrc - fi - - if [ -f "$HOME/.mavenrc" ] ; then - . "$HOME/.mavenrc" - fi - -fi - -# OS specific support. $var _must_ be set to either true or false. -cygwin=false; -darwin=false; -mingw=false -case "`uname`" in - CYGWIN*) cygwin=true ;; - MINGW*) mingw=true;; - Darwin*) darwin=true - # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home - # See https://developer.apple.com/library/mac/qa/qa1170/_index.html - if [ -z "$JAVA_HOME" ]; then - if [ -x "/usr/libexec/java_home" ]; then - export JAVA_HOME="`/usr/libexec/java_home`" - else - export JAVA_HOME="/Library/Java/Home" - fi - fi - ;; -esac - -if [ -z "$JAVA_HOME" ] ; then - if [ -r /etc/gentoo-release ] ; then - JAVA_HOME=`java-config --jre-home` - fi -fi - -if [ -z "$M2_HOME" ] ; then - ## resolve links - $0 may be a link to maven's home - PRG="$0" - - # need this for relative symlinks - while [ -h "$PRG" ] ; do - ls=`ls -ld "$PRG"` - link=`expr "$ls" : '.*-> \(.*\)$'` - if expr "$link" : '/.*' > /dev/null; then - PRG="$link" - else - PRG="`dirname "$PRG"`/$link" - fi - done - - saveddir=`pwd` - - M2_HOME=`dirname "$PRG"`/.. - - # make it fully qualified - M2_HOME=`cd "$M2_HOME" && pwd` - - cd "$saveddir" - # echo Using m2 at $M2_HOME -fi - -# For Cygwin, ensure paths are in UNIX format before anything is touched -if $cygwin ; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --unix "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --unix "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --unix "$CLASSPATH"` -fi - -# For Mingw, ensure paths are in UNIX format before anything is touched -if $mingw ; then - [ -n "$M2_HOME" ] && - M2_HOME="`(cd "$M2_HOME"; pwd)`" - [ -n "$JAVA_HOME" ] && - JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" -fi - -if [ -z "$JAVA_HOME" ]; then - javaExecutable="`which javac`" - if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then - # readlink(1) is not available as standard on Solaris 10. - readLink=`which readlink` - if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then - if $darwin ; then - javaHome="`dirname \"$javaExecutable\"`" - javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" - else - javaExecutable="`readlink -f \"$javaExecutable\"`" - fi - javaHome="`dirname \"$javaExecutable\"`" - javaHome=`expr "$javaHome" : '\(.*\)/bin'` - JAVA_HOME="$javaHome" - export JAVA_HOME - fi - fi -fi - -if [ -z "$JAVACMD" ] ; then - if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD="$JAVA_HOME/jre/sh/java" - else - JAVACMD="$JAVA_HOME/bin/java" - fi - else - JAVACMD="`which java`" - fi -fi - -if [ ! -x "$JAVACMD" ] ; then - echo "Error: JAVA_HOME is not defined correctly." >&2 - echo " We cannot execute $JAVACMD" >&2 - exit 1 -fi - -if [ -z "$JAVA_HOME" ] ; then - echo "Warning: JAVA_HOME environment variable is not set." -fi - -CLASSWORLDS_LAUNCHER=org.codehaus.plexus.classworlds.launcher.Launcher - -# traverses directory structure from process work directory to filesystem root -# first directory with .mvn subdirectory is considered project base directory -find_maven_basedir() { - - if [ -z "$1" ] - then - echo "Path not specified to find_maven_basedir" - return 1 - fi - - basedir="$1" - wdir="$1" - while [ "$wdir" != '/' ] ; do - if [ -d "$wdir"/.mvn ] ; then - basedir=$wdir - break - fi - # workaround for JBEAP-8937 (on Solaris 10/Sparc) - if [ -d "${wdir}" ]; then - wdir=`cd "$wdir/.."; pwd` - fi - # end of workaround - done - echo "${basedir}" -} - -# concatenates all lines of a file -concat_lines() { - if [ -f "$1" ]; then - echo "$(tr -s '\n' ' ' < "$1")" - fi -} - -BASE_DIR=`find_maven_basedir "$(pwd)"` -if [ -z "$BASE_DIR" ]; then - exit 1; -fi - -########################################################################################## -# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -# This allows using the maven wrapper in projects that prohibit checking in binary data. -########################################################################################## -if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found .mvn/wrapper/maven-wrapper.jar" - fi -else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." - fi - if [ -n "$MVNW_REPOURL" ]; then - jarUrl="$MVNW_REPOURL/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - else - jarUrl="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - fi - while IFS="=" read key value; do - case "$key" in (wrapperUrl) jarUrl="$value"; break ;; - esac - done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" - if [ "$MVNW_VERBOSE" = true ]; then - echo "Downloading from: $jarUrl" - fi - wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" - if $cygwin; then - wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` - fi - - if command -v wget > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found wget ... using wget" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - wget "$jarUrl" -O "$wrapperJarPath" - else - wget --http-user=$MVNW_USERNAME --http-password=$MVNW_PASSWORD "$jarUrl" -O "$wrapperJarPath" - fi - elif command -v curl > /dev/null; then - if [ "$MVNW_VERBOSE" = true ]; then - echo "Found curl ... using curl" - fi - if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then - curl -o "$wrapperJarPath" "$jarUrl" -f - else - curl --user $MVNW_USERNAME:$MVNW_PASSWORD -o "$wrapperJarPath" "$jarUrl" -f - fi - - else - if [ "$MVNW_VERBOSE" = true ]; then - echo "Falling back to using Java to download" - fi - javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" - # For Cygwin, switch paths to Windows format before running javac - if $cygwin; then - javaClass=`cygpath --path --windows "$javaClass"` - fi - if [ -e "$javaClass" ]; then - if [ ! -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Compiling MavenWrapperDownloader.java ..." - fi - # Compiling the Java class - ("$JAVA_HOME/bin/javac" "$javaClass") - fi - if [ -e "$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" ]; then - # Running the downloader - if [ "$MVNW_VERBOSE" = true ]; then - echo " - Running MavenWrapperDownloader.java ..." - fi - ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") - fi - fi - fi -fi -########################################################################################## -# End of extension -########################################################################################## - -export MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"} -if [ "$MVNW_VERBOSE" = true ]; then - echo $MAVEN_PROJECTBASEDIR -fi -MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" - -# For Cygwin, switch paths to Windows format before running java -if $cygwin; then - [ -n "$M2_HOME" ] && - M2_HOME=`cygpath --path --windows "$M2_HOME"` - [ -n "$JAVA_HOME" ] && - JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` - [ -n "$CLASSPATH" ] && - CLASSPATH=`cygpath --path --windows "$CLASSPATH"` - [ -n "$MAVEN_PROJECTBASEDIR" ] && - MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` -fi - -# Provide a "standardized" way to retrieve the CLI args that will -# work with both Windows and non-Windows executions. -MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" -export MAVEN_CMD_LINE_ARGS - -WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -exec "$JAVACMD" \ - $MAVEN_OPTS \ - -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ - "-Dmaven.home=${M2_HOME}" "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ - ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd b/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd deleted file mode 100644 index c8d43372..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/mvnw.cmd +++ /dev/null @@ -1,182 +0,0 @@ -@REM ---------------------------------------------------------------------------- -@REM Licensed to the Apache Software Foundation (ASF) under one -@REM or more contributor license agreements. See the NOTICE file -@REM distributed with this work for additional information -@REM regarding copyright ownership. The ASF licenses this file -@REM to you under the Apache License, Version 2.0 (the -@REM "License"); you may not use this file except in compliance -@REM with the License. You may obtain a copy of the License at -@REM -@REM https://www.apache.org/licenses/LICENSE-2.0 -@REM -@REM Unless required by applicable law or agreed to in writing, -@REM software distributed under the License is distributed on an -@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -@REM KIND, either express or implied. See the License for the -@REM specific language governing permissions and limitations -@REM under the License. -@REM ---------------------------------------------------------------------------- - -@REM ---------------------------------------------------------------------------- -@REM Maven Start Up Batch script -@REM -@REM Required ENV vars: -@REM JAVA_HOME - location of a JDK home dir -@REM -@REM Optional ENV vars -@REM M2_HOME - location of maven2's installed home dir -@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands -@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending -@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven -@REM e.g. to debug Maven itself, use -@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 -@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files -@REM ---------------------------------------------------------------------------- - -@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' -@echo off -@REM set title of command window -title %0 -@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' -@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% - -@REM set %HOME% to equivalent of $HOME -if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") - -@REM Execute a user defined script before this one -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre -@REM check for pre script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_pre.bat" call "%HOME%\mavenrc_pre.bat" -if exist "%HOME%\mavenrc_pre.cmd" call "%HOME%\mavenrc_pre.cmd" -:skipRcPre - -@setlocal - -set ERROR_CODE=0 - -@REM To isolate internal variables from possible post scripts, we use another setlocal -@setlocal - -@REM ==== START VALIDATION ==== -if not "%JAVA_HOME%" == "" goto OkJHome - -echo. -echo Error: JAVA_HOME not found in your environment. >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -:OkJHome -if exist "%JAVA_HOME%\bin\java.exe" goto init - -echo. -echo Error: JAVA_HOME is set to an invalid directory. >&2 -echo JAVA_HOME = "%JAVA_HOME%" >&2 -echo Please set the JAVA_HOME variable in your environment to match the >&2 -echo location of your Java installation. >&2 -echo. -goto error - -@REM ==== END VALIDATION ==== - -:init - -@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". -@REM Fallback to current working directory if not found. - -set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% -IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir - -set EXEC_DIR=%CD% -set WDIR=%EXEC_DIR% -:findBaseDir -IF EXIST "%WDIR%"\.mvn goto baseDirFound -cd .. -IF "%WDIR%"=="%CD%" goto baseDirNotFound -set WDIR=%CD% -goto findBaseDir - -:baseDirFound -set MAVEN_PROJECTBASEDIR=%WDIR% -cd "%EXEC_DIR%" -goto endDetectBaseDir - -:baseDirNotFound -set MAVEN_PROJECTBASEDIR=%EXEC_DIR% -cd "%EXEC_DIR%" - -:endDetectBaseDir - -IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig - -@setlocal EnableExtensions EnableDelayedExpansion -for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a -@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% - -:endReadAdditionalConfig - -SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" -set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" -set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain - -set DOWNLOAD_URL="https://repo.maven.apache.org/maven2/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - -FOR /F "tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( - IF "%%A"=="wrapperUrl" SET DOWNLOAD_URL=%%B -) - -@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central -@REM This allows using the maven wrapper in projects that prohibit checking in binary data. -if exist %WRAPPER_JAR% ( - if "%MVNW_VERBOSE%" == "true" ( - echo Found %WRAPPER_JAR% - ) -) else ( - if not "%MVNW_REPOURL%" == "" ( - SET DOWNLOAD_URL="%MVNW_REPOURL%/io/takari/maven-wrapper/0.5.6/maven-wrapper-0.5.6.jar" - ) - if "%MVNW_VERBOSE%" == "true" ( - echo Couldn't find %WRAPPER_JAR%, downloading it ... - echo Downloading from: %DOWNLOAD_URL% - ) - - powershell -Command "&{"^ - "$webclient = new-object System.Net.WebClient;"^ - "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ - "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ - "}"^ - "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%DOWNLOAD_URL%', '%WRAPPER_JAR%')"^ - "}" - if "%MVNW_VERBOSE%" == "true" ( - echo Finished downloading %WRAPPER_JAR% - ) -) -@REM End of extension - -@REM Provide a "standardized" way to retrieve the CLI args that will -@REM work with both Windows and non-Windows executions. -set MAVEN_CMD_LINE_ARGS=%* - -%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %WRAPPER_JAR% "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* -if ERRORLEVEL 1 goto error -goto end - -:error -set ERROR_CODE=1 - -:end -@endlocal & set ERROR_CODE=%ERROR_CODE% - -if not "%MAVEN_SKIP_RC%" == "" goto skipRcPost -@REM check for post script, once with legacy .bat ending and once with .cmd ending -if exist "%HOME%\mavenrc_post.bat" call "%HOME%\mavenrc_post.bat" -if exist "%HOME%\mavenrc_post.cmd" call "%HOME%\mavenrc_post.cmd" -:skipRcPost - -@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' -if "%MAVEN_BATCH_PAUSE%" == "on" pause - -if "%MAVEN_TERMINATE_CMD%" == "on" exit %ERROR_CODE% - -exit /B %ERROR_CODE% diff --git a/reference-dashboard/fiscal-event-aggregator-service/pom.xml b/reference-dashboard/fiscal-event-aggregator-service/pom.xml deleted file mode 100644 index 4edc5e81..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/pom.xml +++ /dev/null @@ -1,68 +0,0 @@ - - - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.5.4 - - - org.egov - fiscal-event-aggregator-service - 0.0.1-SNAPSHOT - fiscal-event-aggregator-service - Aggregate the fiscal event post processed data - - 1.8 - - - - org.springframework.boot - spring-boot-starter - - - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-starter-jdbc - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - in.zapr.druid - druidry - 3.1 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - - - diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java deleted file mode 100644 index 79a4e04b..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplication.java +++ /dev/null @@ -1,15 +0,0 @@ -package org.egov.fiscaleventaggregatorservice; - -import lombok.Data; -import org.springframework.boot.SpringApplication; -import org.springframework.boot.autoconfigure.SpringBootApplication; - -@SpringBootApplication -@Data -public class FiscalEventAggregatorServiceApplication { - - public static void main(String[] args) { - SpringApplication.run(FiscalEventAggregatorServiceApplication.class, args); - } - -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java deleted file mode 100644 index f48e0427..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/ConfigProperties.java +++ /dev/null @@ -1,28 +0,0 @@ -package org.egov.fiscaleventaggregatorservice.config; - -import lombok.Data; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.stereotype.Component; - -@Component -@Data -public class ConfigProperties { - - @Value("${druid.host}") - private String druidHost; - - @Value("${druid.endPoint}") - private String druidEndPoint; - - @Value("${spring.datasource.driver-class-name}") - private String postgresDatasourceDriverClassName; - - @Value("${spring.datasource.url}") - private String postgresDatasourceUrl; - - @Value("${spring.datasource.username}") - private String postgresDatasourceUsername; - - @Value("${spring.datasource.password}") - private String postgresDatasourcePassword; -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java deleted file mode 100644 index f915c44a..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/config/FiscalEventConfiguration.java +++ /dev/null @@ -1,59 +0,0 @@ -package org.egov.fiscaleventaggregatorservice.config; - -import in.zapr.druid.druidry.client.DruidClient; -import in.zapr.druid.druidry.client.DruidConfiguration; -import in.zapr.druid.druidry.client.DruidJerseyClient; -import in.zapr.druid.druidry.client.exception.ConnectionException; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DriverManagerDataSource; - -import javax.sql.DataSource; - -@Configuration -public class FiscalEventConfiguration { - - @Autowired - private ConfigProperties configProperties; - - @Bean - public DruidClient getDruidClient() { - DruidConfiguration config = DruidConfiguration - .builder() - .host(configProperties.getDruidHost()) - .endpoint(configProperties.getDruidEndPoint()) - .build(); - - DruidClient client = new DruidJerseyClient(config); - try { - System.out.println("Druid Client : " + client); - client.connect(); - } catch (ConnectionException e) { - e.printStackTrace(); - } - //List responses = client.query(query, DruidResponse.class); -// try { -// client.close(); -// } catch (ConnectionException e) { -// e.printStackTrace(); -// } - return client; - } - - public DataSource getDS() { - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName(configProperties.getPostgresDatasourceDriverClassName()); - dataSource.setUrl(configProperties.getPostgresDatasourceUrl()); - dataSource.setUsername(configProperties.getPostgresDatasourceUsername()); - dataSource.setPassword(configProperties.getPostgresDatasourcePassword()); - return dataSource; - } - - - @Bean - public JdbcTemplate getJdbcTemplate() { - return new JdbcTemplate(getDS()); - } -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java deleted file mode 100644 index c0e33d71..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/DruidDataQueryProcessor.java +++ /dev/null @@ -1,92 +0,0 @@ -package org.egov.fiscaleventaggregatorservice.processor; - - -import in.zapr.druid.druidry.aggregator.DoubleSumAggregator; -import in.zapr.druid.druidry.aggregator.DruidAggregator; -import in.zapr.druid.druidry.aggregator.LongSumAggregator; -import in.zapr.druid.druidry.client.DruidClient; -import in.zapr.druid.druidry.client.exception.QueryException; -import in.zapr.druid.druidry.dataSource.TableDataSource; -import in.zapr.druid.druidry.dimension.DruidDimension; -import in.zapr.druid.druidry.dimension.SimpleDimension; -import in.zapr.druid.druidry.granularity.Granularity; -import in.zapr.druid.druidry.granularity.PredefinedGranularity; -import in.zapr.druid.druidry.granularity.SimpleGranularity; -import in.zapr.druid.druidry.postAggregator.ArithmeticFunction; -import in.zapr.druid.druidry.postAggregator.ArithmeticPostAggregator; -import in.zapr.druid.druidry.postAggregator.DruidPostAggregator; -import in.zapr.druid.druidry.postAggregator.FieldAccessPostAggregator; -import in.zapr.druid.druidry.query.aggregation.DruidTopNQuery; -import in.zapr.druid.druidry.query.config.Interval; -import in.zapr.druid.druidry.topNMetric.SimpleMetric; -import in.zapr.druid.druidry.topNMetric.TopNMetric; -import org.joda.time.DateTime; -import org.joda.time.DateTimeZone; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.stereotype.Component; - -import java.util.Arrays; -import java.util.Collections; -import java.util.List; - -@Component -public class DruidDataQueryProcessor { - - @Autowired - private DruidClient druidClient; - - - //TODO - public void fetchFiscalEventFromDruid() { - System.out.println("*********** Druid_client : " + druidClient); - - TableDataSource dataSource = new TableDataSource("fiscal-event"); -// SelectorFilter selectorFilter1 = new SelectorFilter("dim1", "some_value"); -// SelectorFilter selectorFilter2 = new SelectorFilter("dim2", "some_other_val"); -// -// AndFilter filter = new AndFilter(Arrays.asList(selectorFilter1, selectorFilter2)); - - DruidAggregator aggregator1 = new LongSumAggregator("count", "count"); - DruidAggregator aggregator2 = new DoubleSumAggregator("some_metric", "some_metric"); - - FieldAccessPostAggregator fieldAccessPostAggregator1 - = new FieldAccessPostAggregator("some_metric", "some_metric"); - - FieldAccessPostAggregator fieldAccessPostAggregator2 - = new FieldAccessPostAggregator("count", "count"); - - DruidPostAggregator postAggregator = ArithmeticPostAggregator.builder() - .name("sample_divide") - .function(ArithmeticFunction.DIVIDE) - .fields(Arrays.asList(fieldAccessPostAggregator1, fieldAccessPostAggregator2)) - .build(); - - DateTime startTime = new DateTime(2013, 8, 31, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(2013, 9, 3, 0, 0, 0, DateTimeZone.UTC); - Interval interval = new Interval(startTime, endTime); - - Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); - DruidDimension dimension = new SimpleDimension("sample_dim"); - TopNMetric metric = new SimpleMetric("count"); - - DruidTopNQuery query = DruidTopNQuery.builder() - .dataSource(dataSource) - .dimension(dimension) - .threshold(5) - .topNMetric(metric) - .granularity(granularity) - .filter(null) - .aggregators(Arrays.asList(aggregator1, aggregator2)) - .postAggregators(Collections.singletonList(postAggregator)) - .intervals(Collections.singletonList(interval)) - .build(); - - try { - List responses = druidClient.query(query, Object.class); - } catch (QueryException e) { - e.printStackTrace(); - } - - - } -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java b/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java deleted file mode 100644 index 8fac35b2..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/java/org/egov/fiscaleventaggregatorservice/processor/FiscalEventAggregateProcessor.java +++ /dev/null @@ -1,20 +0,0 @@ -package org.egov.fiscaleventaggregatorservice.processor; - -import lombok.extern.slf4j.Slf4j; -import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.boot.ApplicationArguments; -import org.springframework.boot.ApplicationRunner; -import org.springframework.stereotype.Component; - -@Slf4j -@Component -public class FiscalEventAggregateProcessor implements ApplicationRunner { - - @Autowired - private DruidDataQueryProcessor druidDataQueryProcessor; - - @Override - public void run(ApplicationArguments args) throws Exception { - druidDataQueryProcessor.fetchFiscalEventFromDruid(); - } -} diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties deleted file mode 100644 index 63caf57d..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/application.properties +++ /dev/null @@ -1,8 +0,0 @@ -spring.datasource.driver-class-name=org.postgresql.Driver -spring.datasource.url=jdbc:postgresql://localhost:5432/fiscal_event -spring.datasource.username=postgres -spring.datasource.password=root - -## Druid Config ## -druid.host=https://druid-qa.ifix.org.in/ -druid.endPoint=druid/v2/ diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql deleted file mode 100644 index 0f4b16ce..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql +++ /dev/null @@ -1,83 +0,0 @@ -DROP TABLE IF EXISTS fiscal_event_aggregated; - -CREATE TABLE fiscal_event_aggregated( - ver TEXT, - id SERIAL, - tenantId TEXT, - government_id TEXT, - government_name TEXT, - eventType TEXT, - sumAmount DECIMAL, - fiscalPeriod TEXT, - count bigint, - department_id TEXT, - department_code TEXT, - department_name TEXT, - departmentEntity_ancestry_0_id TEXT, - departmentEntity_ancestry_0_code TEXT, - departmentEntity_ancestry_0_name TEXT, - departmentEntity_ancestry_0_hierarchyLevel integer, - departmentEntity_ancestry_1_id TEXT, - departmentEntity_ancestry_1_code TEXT, - departmentEntity_ancestry_1_name TEXT, - departmentEntity_ancestry_1_hierarchyLevel integer, - departmentEntity_ancestry_2_id TEXT, - departmentEntity_ancestry_2_code TEXT, - departmentEntity_ancestry_2_name TEXT, - departmentEntity_ancestry_2_hierarchyLevel integer, - departmentEntity_ancestry_3_id TEXT, - departmentEntity_ancestry_3_code TEXT, - departmentEntity_ancestry_3_name TEXT, - departmentEntity_ancestry_3_hierarchyLevel integer, - departmentEntity_ancestry_4_id TEXT, - departmentEntity_ancestry_4_code TEXT, - departmentEntity_ancestry_4_name TEXT, - departmentEntity_ancestry_4_hierarchyLevel integer, - departmentEntity_ancestry_5_id TEXT, - departmentEntity_ancestry_5_code TEXT, - departmentEntity_ancestry_5_name TEXT, - departmentEntity_ancestry_5_hierarchyLevel integer, - departmentEntity_ancestry_6_id TEXT, - departmentEntity_ancestry_6_code TEXT, - departmentEntity_ancestry_6_name TEXT, - departmentEntity_ancestry_6_hierarchyLevel integer, - departmentEntity_ancestry_7_id TEXT, - departmentEntity_ancestry_7_code TEXT, - departmentEntity_ancestry_7_name TEXT, - departmentEntity_ancestry_7_hierarchyLevel integer, - departmentEntity_ancestry_8_id TEXT, - departmentEntity_ancestry_8_code TEXT, - departmentEntity_ancestry_8_name TEXT, - departmentEntity_ancestry_8_hierarchyLevel integer, - departmentEntity_ancestry_9_id TEXT, - departmentEntity_ancestry_9_code TEXT, - departmentEntity_ancestry_9_name TEXT, - departmentEntity_ancestry_9_hierarchyLevel integer, - departmentEntity_ancestry_10_id TEXT, - departmentEntity_ancestry_10_code TEXT, - departmentEntity_ancestry_10_name TEXT, - departmentEntity_ancestry_10_hierarchyLevel integer, - expenditure_id TEXT, - expenditure_code TEXT, - expenditure_name TEXT, - expenditure_type TEXT, - project_id TEXT, - project_code TEXT, - project_name TEXT, - coa_id TEXT, - coa_coaCode TEXT, - coa_majorHead TEXT, - coa_majorHeadName TEXT, - coa_majorHeadType TEXT, - coa_subMajorHead TEXT, - coa_subMajorHeadName TEXT, - coa_minorHead TEXT, - coa_minorHeadName TEXT, - coa_subHead TEXT, - coa_subHeadName TEXT, - coa_groupHead TEXT, - coa_groupHeadName TEXT, - coa_objectHead TEXT, - coa_objectHeadName TEXT, - PRIMARY KEY (id) -); \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java b/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java deleted file mode 100644 index a20d2ae4..00000000 --- a/reference-dashboard/fiscal-event-aggregator-service/src/test/java/org/egov/fiscaleventaggregatorservice/FiscalEventAggregatorServiceApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.egov.fiscaleventaggregatorservice; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class FiscalEventAggregatorServiceApplicationTests { - -// @Test -// void contextLoads() { -// } - -} From 757458c76c91c821d7b74ddc67b39da84c6ac8bd Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Thu, 16 Sep 2021 10:53:30 +0530 Subject: [PATCH 50/67] reanmed the service --- .../fiscal-event-aggregator/.gitignore | 33 +++++ .../fiscal-event-aggregator/pom.xml | 68 +++++++++++ .../FiscalEventAggregatorApplication.java | 15 +++ .../aggregate/config/ConfigProperties.java | 28 +++++ .../config/FiscalEventConfiguration.java | 61 ++++++++++ .../processor/DruidDataQueryProcessor.java | 113 ++++++++++++++++++ .../FiscalEventAggregateProcessor.java | 20 ++++ .../src/main/resources/application.properties | 8 ++ .../main/resources/db/migration/Dockerfile | 9 ++ ...20210914173000__fiscal_event_aggregate.sql | 83 +++++++++++++ .../main/resources/db/migration/migrate.sh | 3 + ...ventAggregatorServiceApplicationTests.java | 13 ++ 12 files changed, 454 insertions(+) create mode 100644 reference-dashboard/fiscal-event-aggregator/.gitignore create mode 100644 reference-dashboard/fiscal-event-aggregator/pom.xml create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh create mode 100644 reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java diff --git a/reference-dashboard/fiscal-event-aggregator/.gitignore b/reference-dashboard/fiscal-event-aggregator/.gitignore new file mode 100644 index 00000000..549e00a2 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/.gitignore @@ -0,0 +1,33 @@ +HELP.md +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### STS ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ diff --git a/reference-dashboard/fiscal-event-aggregator/pom.xml b/reference-dashboard/fiscal-event-aggregator/pom.xml new file mode 100644 index 00000000..313c92dc --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/pom.xml @@ -0,0 +1,68 @@ + + + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + org.egov + fiscal-event-aggregator + 0.0.1-SNAPSHOT + fiscal-event-aggregator + Aggregate the fiscal event post processed data + + 1.8 + + + + org.springframework.boot + spring-boot-starter + + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + in.zapr.druid + druidry + 3.1 + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + + + diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java new file mode 100644 index 00000000..49757c7a --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/FiscalEventAggregatorApplication.java @@ -0,0 +1,15 @@ +package org.egov; + +import lombok.Data; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@Data +public class FiscalEventAggregatorApplication { + + public static void main(String[] args) { + SpringApplication.run(FiscalEventAggregatorApplication.class, args); + } + +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java new file mode 100644 index 00000000..f486c4bd --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -0,0 +1,28 @@ +package org.egov.ifix.aggregate.config; + +import lombok.Data; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +@Data +public class ConfigProperties { + + @Value("${druid.host}") + private String druidHost; + + @Value("${druid.endPoint}") + private String druidEndPoint; + + @Value("${spring.datasource.driver-class-name}") + private String postgresDatasourceDriverClassName; + + @Value("${spring.datasource.url}") + private String postgresDatasourceUrl; + + @Value("${spring.datasource.username}") + private String postgresDatasourceUsername; + + @Value("${spring.datasource.password}") + private String postgresDatasourcePassword; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java new file mode 100644 index 00000000..90082c8f --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java @@ -0,0 +1,61 @@ +package org.egov.ifix.aggregate.config; + +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.DruidConfiguration; +import in.zapr.druid.druidry.client.DruidJerseyClient; +import in.zapr.druid.druidry.client.DruidQueryProtocol; +import in.zapr.druid.druidry.client.exception.ConnectionException; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.datasource.DriverManagerDataSource; + +import javax.sql.DataSource; + +@Configuration +public class FiscalEventConfiguration { + + @Autowired + private ConfigProperties configProperties; + + @Bean + public DruidClient getDruidClient() { + DruidConfiguration config = DruidConfiguration + .builder() + .protocol(DruidQueryProtocol.HTTPS) + .host(configProperties.getDruidHost()) + .endpoint(configProperties.getDruidEndPoint()) + .build(); + + DruidClient client = new DruidJerseyClient(config); + try { + System.out.println("Druid Client : " + client); + client.connect(); + } catch (ConnectionException e) { + e.printStackTrace(); + } + //List responses = client.query(query, DruidResponse.class); +// try { +// client.close(); +// } catch (ConnectionException e) { +// e.printStackTrace(); +// } + return client; + } + + public DataSource getDS() { + DriverManagerDataSource dataSource = new DriverManagerDataSource(); + dataSource.setDriverClassName(configProperties.getPostgresDatasourceDriverClassName()); + dataSource.setUrl(configProperties.getPostgresDatasourceUrl()); + dataSource.setUsername(configProperties.getPostgresDatasourceUsername()); + dataSource.setPassword(configProperties.getPostgresDatasourcePassword()); + return dataSource; + } + + + @Bean + public JdbcTemplate getJdbcTemplate() { + return new JdbcTemplate(getDS()); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java new file mode 100644 index 00000000..66ba73f4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -0,0 +1,113 @@ +package org.egov.ifix.aggregate.processor; + + +import in.zapr.druid.druidry.aggregator.CountAggregator; +import in.zapr.druid.druidry.aggregator.DoubleSumAggregator; +import in.zapr.druid.druidry.aggregator.DruidAggregator; +import in.zapr.druid.druidry.aggregator.LongSumAggregator; +import in.zapr.druid.druidry.client.DruidClient; +import in.zapr.druid.druidry.client.exception.QueryException; +import in.zapr.druid.druidry.dataSource.TableDataSource; +import in.zapr.druid.druidry.dimension.DefaultDimension; +import in.zapr.druid.druidry.dimension.DimensionSpec; +import in.zapr.druid.druidry.dimension.DruidDimension; +import in.zapr.druid.druidry.dimension.SimpleDimension; +import in.zapr.druid.druidry.dimension.enums.OutputType; +import in.zapr.druid.druidry.granularity.Granularity; +import in.zapr.druid.druidry.granularity.PredefinedGranularity; +import in.zapr.druid.druidry.granularity.SimpleGranularity; +import in.zapr.druid.druidry.postAggregator.ArithmeticFunction; +import in.zapr.druid.druidry.postAggregator.ArithmeticPostAggregator; +import in.zapr.druid.druidry.postAggregator.DruidPostAggregator; +import in.zapr.druid.druidry.postAggregator.FieldAccessPostAggregator; +import in.zapr.druid.druidry.query.DruidQuery; +import in.zapr.druid.druidry.query.aggregation.DruidGroupByQuery; +import in.zapr.druid.druidry.query.aggregation.DruidTopNQuery; +import in.zapr.druid.druidry.query.config.Interval; +import in.zapr.druid.druidry.topNMetric.SimpleMetric; +import in.zapr.druid.druidry.topNMetric.TopNMetric; +import org.joda.time.DateTime; +import org.joda.time.DateTimeZone; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +@Component +public class DruidDataQueryProcessor { + + @Autowired + private DruidClient druidClient; + + + //TODO + public void fetchFiscalEventFromDruid() { + System.out.println("*********** Druid_client : " + druidClient); + + TableDataSource dataSource = new TableDataSource("fiscal-event"); + DateTime startTime = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(2021, 12, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + DruidDimension dimension1 = new DefaultDimension("project.id","project.id", OutputType.STRING); + DruidDimension dimension2 = new DefaultDimension("coa.id","coa.id", OutputType.STRING); + DruidDimension dimension3 = new DefaultDimension("eventType","eventType", OutputType.STRING); + List druidDimensions = new ArrayList<>(); + druidDimensions.add(dimension1); + druidDimensions.add(dimension2); + druidDimensions.add(dimension3); +// SelectorFilter selectorFilter1 = new SelectorFilter("dim1", "some_value"); +// SelectorFilter selectorFilter2 = new SelectorFilter("dim2", "some_other_val"); +// +// AndFilter filter = new AndFilter(Arrays.asList(selectorFilter1, selectorFilter2)); + + DruidAggregator aggregator1 = new CountAggregator("Count"); + DruidAggregator aggregator2 = new DoubleSumAggregator("amount", "amount"); + List aggregators = new ArrayList<>(); + aggregators.add(aggregator1); + aggregators.add(aggregator2); + +// FieldAccessPostAggregator fieldAccessPostAggregator1 +// = new FieldAccessPostAggregator("some_metric", "some_metric"); +// +// FieldAccessPostAggregator fieldAccessPostAggregator2 +// = new FieldAccessPostAggregator("count", "count"); + +// DruidPostAggregator postAggregator = ArithmeticPostAggregator.builder() +// .name("sample_divide") +// .function(ArithmeticFunction.DIVIDE) +// .fields(Arrays.asList(fieldAccessPostAggregator1, fieldAccessPostAggregator2)) +// .build(); + + + + + + TopNMetric metric = new SimpleMetric("count"); + + DruidQuery query = DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + //.threshold(5) + // .topNMetric(metric) + .granularity(granularity) + .filter(null) + .aggregators(aggregators) + // .postAggregators(Collections.singletonList(postAggregator)) + .intervals(Collections.singletonList(interval)) + .build(); +// String responses = null; +// try { +// responses = druidClient.query(query); +// } catch (QueryException e) { +// e.printStackTrace(); +// } +// +// System.out.println("Response : "+responses); + + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java new file mode 100644 index 00000000..badba851 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java @@ -0,0 +1,20 @@ +package org.egov.ifix.aggregate.processor; + +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.ApplicationArguments; +import org.springframework.boot.ApplicationRunner; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +public class FiscalEventAggregateProcessor implements ApplicationRunner { + + @Autowired + private DruidDataQueryProcessor druidDataQueryProcessor; + + @Override + public void run(ApplicationArguments args) throws Exception { + druidDataQueryProcessor.fetchFiscalEventFromDruid(); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties new file mode 100644 index 00000000..a0e0a799 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -0,0 +1,8 @@ +spring.datasource.driver-class-name=org.postgresql.Driver +spring.datasource.url=jdbc:postgresql://localhost:5432/fiscal_event +spring.datasource.username=postgres +spring.datasource.password=postgres + +## Druid Config ## +druid.host=druid-qa.ifix.org.in +druid.endPoint=druid/v2/ diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile new file mode 100644 index 00000000..a5699ff7 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile @@ -0,0 +1,9 @@ +FROM egovio/flyway:4.1.2 + +COPY ./migration/main /flyway/sql + +COPY migrate.sh /usr/bin/migrate.sh + +RUN chmod +x /usr/bin/migrate.sh + +CMD ["/usr/bin/migrate.sh"] diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql new file mode 100644 index 00000000..0f4b16ce --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql @@ -0,0 +1,83 @@ +DROP TABLE IF EXISTS fiscal_event_aggregated; + +CREATE TABLE fiscal_event_aggregated( + ver TEXT, + id SERIAL, + tenantId TEXT, + government_id TEXT, + government_name TEXT, + eventType TEXT, + sumAmount DECIMAL, + fiscalPeriod TEXT, + count bigint, + department_id TEXT, + department_code TEXT, + department_name TEXT, + departmentEntity_ancestry_0_id TEXT, + departmentEntity_ancestry_0_code TEXT, + departmentEntity_ancestry_0_name TEXT, + departmentEntity_ancestry_0_hierarchyLevel integer, + departmentEntity_ancestry_1_id TEXT, + departmentEntity_ancestry_1_code TEXT, + departmentEntity_ancestry_1_name TEXT, + departmentEntity_ancestry_1_hierarchyLevel integer, + departmentEntity_ancestry_2_id TEXT, + departmentEntity_ancestry_2_code TEXT, + departmentEntity_ancestry_2_name TEXT, + departmentEntity_ancestry_2_hierarchyLevel integer, + departmentEntity_ancestry_3_id TEXT, + departmentEntity_ancestry_3_code TEXT, + departmentEntity_ancestry_3_name TEXT, + departmentEntity_ancestry_3_hierarchyLevel integer, + departmentEntity_ancestry_4_id TEXT, + departmentEntity_ancestry_4_code TEXT, + departmentEntity_ancestry_4_name TEXT, + departmentEntity_ancestry_4_hierarchyLevel integer, + departmentEntity_ancestry_5_id TEXT, + departmentEntity_ancestry_5_code TEXT, + departmentEntity_ancestry_5_name TEXT, + departmentEntity_ancestry_5_hierarchyLevel integer, + departmentEntity_ancestry_6_id TEXT, + departmentEntity_ancestry_6_code TEXT, + departmentEntity_ancestry_6_name TEXT, + departmentEntity_ancestry_6_hierarchyLevel integer, + departmentEntity_ancestry_7_id TEXT, + departmentEntity_ancestry_7_code TEXT, + departmentEntity_ancestry_7_name TEXT, + departmentEntity_ancestry_7_hierarchyLevel integer, + departmentEntity_ancestry_8_id TEXT, + departmentEntity_ancestry_8_code TEXT, + departmentEntity_ancestry_8_name TEXT, + departmentEntity_ancestry_8_hierarchyLevel integer, + departmentEntity_ancestry_9_id TEXT, + departmentEntity_ancestry_9_code TEXT, + departmentEntity_ancestry_9_name TEXT, + departmentEntity_ancestry_9_hierarchyLevel integer, + departmentEntity_ancestry_10_id TEXT, + departmentEntity_ancestry_10_code TEXT, + departmentEntity_ancestry_10_name TEXT, + departmentEntity_ancestry_10_hierarchyLevel integer, + expenditure_id TEXT, + expenditure_code TEXT, + expenditure_name TEXT, + expenditure_type TEXT, + project_id TEXT, + project_code TEXT, + project_name TEXT, + coa_id TEXT, + coa_coaCode TEXT, + coa_majorHead TEXT, + coa_majorHeadName TEXT, + coa_majorHeadType TEXT, + coa_subMajorHead TEXT, + coa_subMajorHeadName TEXT, + coa_minorHead TEXT, + coa_minorHeadName TEXT, + coa_subHead TEXT, + coa_subHeadName TEXT, + coa_groupHead TEXT, + coa_groupHeadName TEXT, + coa_objectHead TEXT, + coa_objectHeadName TEXT, + PRIMARY KEY (id) +); \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh new file mode 100644 index 00000000..43960b25 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java b/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java new file mode 100644 index 00000000..1bf1ea9a --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java @@ -0,0 +1,13 @@ +package org.egov.ifix.aggregate; + +import org.junit.jupiter.api.Test; +import org.springframework.boot.test.context.SpringBootTest; + +@SpringBootTest +class FiscalEventAggregatorServiceApplicationTests { + +// @Test +// void contextLoads() { +// } + +} From 13dbe4971434ac4e715f05394606a2f1314defc1 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Thu, 16 Sep 2021 11:00:57 +0530 Subject: [PATCH 51/67] Moved to db folder --- .../src/main/resources/db/{migration => }/Dockerfile | 0 .../src/main/resources/db/{migration => }/migrate.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename reference-dashboard/fiscal-event-aggregator/src/main/resources/db/{migration => }/Dockerfile (100%) rename reference-dashboard/fiscal-event-aggregator/src/main/resources/db/{migration => }/migrate.sh (100%) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile similarity index 100% rename from reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/Dockerfile rename to reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh similarity index 100% rename from reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/migrate.sh rename to reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh From c6b4a74f5346058b5ddd57d401317018c1216cd0 Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Thu, 16 Sep 2021 11:06:03 +0530 Subject: [PATCH 52/67] Re-indented .sql flie --- ...20210914173000__fiscal_event_aggregate.sql | 160 +++++++++--------- 1 file changed, 80 insertions(+), 80 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql index 0f4b16ce..6be42a66 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql @@ -1,83 +1,83 @@ DROP TABLE IF EXISTS fiscal_event_aggregated; CREATE TABLE fiscal_event_aggregated( - ver TEXT, - id SERIAL, - tenantId TEXT, - government_id TEXT, - government_name TEXT, - eventType TEXT, - sumAmount DECIMAL, - fiscalPeriod TEXT, - count bigint, - department_id TEXT, - department_code TEXT, - department_name TEXT, - departmentEntity_ancestry_0_id TEXT, - departmentEntity_ancestry_0_code TEXT, - departmentEntity_ancestry_0_name TEXT, - departmentEntity_ancestry_0_hierarchyLevel integer, - departmentEntity_ancestry_1_id TEXT, - departmentEntity_ancestry_1_code TEXT, - departmentEntity_ancestry_1_name TEXT, - departmentEntity_ancestry_1_hierarchyLevel integer, - departmentEntity_ancestry_2_id TEXT, - departmentEntity_ancestry_2_code TEXT, - departmentEntity_ancestry_2_name TEXT, - departmentEntity_ancestry_2_hierarchyLevel integer, - departmentEntity_ancestry_3_id TEXT, - departmentEntity_ancestry_3_code TEXT, - departmentEntity_ancestry_3_name TEXT, - departmentEntity_ancestry_3_hierarchyLevel integer, - departmentEntity_ancestry_4_id TEXT, - departmentEntity_ancestry_4_code TEXT, - departmentEntity_ancestry_4_name TEXT, - departmentEntity_ancestry_4_hierarchyLevel integer, - departmentEntity_ancestry_5_id TEXT, - departmentEntity_ancestry_5_code TEXT, - departmentEntity_ancestry_5_name TEXT, - departmentEntity_ancestry_5_hierarchyLevel integer, - departmentEntity_ancestry_6_id TEXT, - departmentEntity_ancestry_6_code TEXT, - departmentEntity_ancestry_6_name TEXT, - departmentEntity_ancestry_6_hierarchyLevel integer, - departmentEntity_ancestry_7_id TEXT, - departmentEntity_ancestry_7_code TEXT, - departmentEntity_ancestry_7_name TEXT, - departmentEntity_ancestry_7_hierarchyLevel integer, - departmentEntity_ancestry_8_id TEXT, - departmentEntity_ancestry_8_code TEXT, - departmentEntity_ancestry_8_name TEXT, - departmentEntity_ancestry_8_hierarchyLevel integer, - departmentEntity_ancestry_9_id TEXT, - departmentEntity_ancestry_9_code TEXT, - departmentEntity_ancestry_9_name TEXT, - departmentEntity_ancestry_9_hierarchyLevel integer, - departmentEntity_ancestry_10_id TEXT, - departmentEntity_ancestry_10_code TEXT, - departmentEntity_ancestry_10_name TEXT, - departmentEntity_ancestry_10_hierarchyLevel integer, - expenditure_id TEXT, - expenditure_code TEXT, - expenditure_name TEXT, - expenditure_type TEXT, - project_id TEXT, - project_code TEXT, - project_name TEXT, - coa_id TEXT, - coa_coaCode TEXT, - coa_majorHead TEXT, - coa_majorHeadName TEXT, - coa_majorHeadType TEXT, - coa_subMajorHead TEXT, - coa_subMajorHeadName TEXT, - coa_minorHead TEXT, - coa_minorHeadName TEXT, - coa_subHead TEXT, - coa_subHeadName TEXT, - coa_groupHead TEXT, - coa_groupHeadName TEXT, - coa_objectHead TEXT, - coa_objectHeadName TEXT, - PRIMARY KEY (id) -); \ No newline at end of file + ver TEXT, + id SERIAL, + tenantId TEXT, + government_id TEXT, + government_name TEXT, + eventType TEXT, + sumAmount DECIMAL, + fiscalPeriod TEXT, + count bigint, + department_id TEXT, + department_code TEXT, + department_name TEXT, + departmentEntity_ancestry_0_id TEXT, + departmentEntity_ancestry_0_code TEXT, + departmentEntity_ancestry_0_name TEXT, + departmentEntity_ancestry_0_hierarchyLevel integer, + departmentEntity_ancestry_1_id TEXT, + departmentEntity_ancestry_1_code TEXT, + departmentEntity_ancestry_1_name TEXT, + departmentEntity_ancestry_1_hierarchyLevel integer, + departmentEntity_ancestry_2_id TEXT, + departmentEntity_ancestry_2_code TEXT, + departmentEntity_ancestry_2_name TEXT, + departmentEntity_ancestry_2_hierarchyLevel integer, + departmentEntity_ancestry_3_id TEXT, + departmentEntity_ancestry_3_code TEXT, + departmentEntity_ancestry_3_name TEXT, + departmentEntity_ancestry_3_hierarchyLevel integer, + departmentEntity_ancestry_4_id TEXT, + departmentEntity_ancestry_4_code TEXT, + departmentEntity_ancestry_4_name TEXT, + departmentEntity_ancestry_4_hierarchyLevel integer, + departmentEntity_ancestry_5_id TEXT, + departmentEntity_ancestry_5_code TEXT, + departmentEntity_ancestry_5_name TEXT, + departmentEntity_ancestry_5_hierarchyLevel integer, + departmentEntity_ancestry_6_id TEXT, + departmentEntity_ancestry_6_code TEXT, + departmentEntity_ancestry_6_name TEXT, + departmentEntity_ancestry_6_hierarchyLevel integer, + departmentEntity_ancestry_7_id TEXT, + departmentEntity_ancestry_7_code TEXT, + departmentEntity_ancestry_7_name TEXT, + departmentEntity_ancestry_7_hierarchyLevel integer, + departmentEntity_ancestry_8_id TEXT, + departmentEntity_ancestry_8_code TEXT, + departmentEntity_ancestry_8_name TEXT, + departmentEntity_ancestry_8_hierarchyLevel integer, + departmentEntity_ancestry_9_id TEXT, + departmentEntity_ancestry_9_code TEXT, + departmentEntity_ancestry_9_name TEXT, + departmentEntity_ancestry_9_hierarchyLevel integer, + departmentEntity_ancestry_10_id TEXT, + departmentEntity_ancestry_10_code TEXT, + departmentEntity_ancestry_10_name TEXT, + departmentEntity_ancestry_10_hierarchyLevel integer, + expenditure_id TEXT, + expenditure_code TEXT, + expenditure_name TEXT, + expenditure_type TEXT, + project_id TEXT, + project_code TEXT, + project_name TEXT, + coa_id TEXT, + coa_coaCode TEXT, + coa_majorHead TEXT, + coa_majorHeadName TEXT, + coa_majorHeadType TEXT, + coa_subMajorHead TEXT, + coa_subMajorHeadName TEXT, + coa_minorHead TEXT, + coa_minorHeadName TEXT, + coa_subHead TEXT, + coa_subHeadName TEXT, + coa_groupHead TEXT, + coa_groupHeadName TEXT, + coa_objectHead TEXT, + coa_objectHeadName TEXT, + PRIMARY KEY (id) +); From 6da5161525bbac250c16140f944dc58bf3f5d733 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Wed, 22 Sep 2021 10:46:41 +0530 Subject: [PATCH 53/67] first version of fiscal event aggregate --- .../fiscal-event-aggregator/pom.xml | 133 ++++---- .../aggregate/config/ConfigProperties.java | 18 + .../config/FiscalEventConfiguration.java | 25 +- .../aggregate/model/FiscalEventAggregate.java | 99 ++++++ .../processor/DruidDataQueryProcessor.java | 241 ++++++++++---- .../FiscalEventAggregateRepository.java | 25 ++ .../mapper/FiscalEventAggregateQuery.java | 81 +++++ .../FiscalEventAggregatedDataMapper.java | 241 ++++++++++++++ .../util/FiscalEventAggregateConstants.java | 12 + .../util/FiscalEventAggregateUtil.java | 312 ++++++++++++++++++ .../src/main/resources/application.properties | 25 +- ...0210921173000__fiscal_event_aggregate.sql} | 21 +- 12 files changed, 1094 insertions(+), 139 deletions(-) create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java rename reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/{V20210914173000__fiscal_event_aggregate.sql => V20210921173000__fiscal_event_aggregate.sql} (93%) diff --git a/reference-dashboard/fiscal-event-aggregator/pom.xml b/reference-dashboard/fiscal-event-aggregator/pom.xml index 313c92dc..f26b2c60 100644 --- a/reference-dashboard/fiscal-event-aggregator/pom.xml +++ b/reference-dashboard/fiscal-event-aggregator/pom.xml @@ -1,68 +1,75 @@ - 4.0.0 - - org.springframework.boot - spring-boot-starter-parent - 2.5.4 - - - org.egov - fiscal-event-aggregator - 0.0.1-SNAPSHOT - fiscal-event-aggregator - Aggregate the fiscal event post processed data - - 1.8 - - - - org.springframework.boot - spring-boot-starter - + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> + 4.0.0 + + org.springframework.boot + spring-boot-starter-parent + 2.5.4 + + + org.egov + fiscal-event-aggregator + 0.1.0-SNAPSHOT + fiscal-event-aggregator + Aggregate the fiscal event post processed data + + 1.8 + + + + org.springframework.boot + spring-boot-starter + + + org.flywaydb + flyway-core + + + org.postgresql + postgresql + runtime + + + org.springframework.boot + spring-boot-starter-jdbc + + + org.projectlombok + lombok + true + + + org.springframework.boot + spring-boot-starter-test + test + + + in.zapr.druid + druidry + 3.1 + + + com.fasterxml.jackson.datatype + jackson-datatype-jsr310 + + - - org.postgresql - postgresql - runtime - - - org.springframework.boot - spring-boot-starter-jdbc - - - org.projectlombok - lombok - true - - - org.springframework.boot - spring-boot-starter-test - test - - - in.zapr.druid - druidry - 3.1 - - - - - - - org.springframework.boot - spring-boot-maven-plugin - - - - org.projectlombok - lombok - - - - - - + + + + org.springframework.boot + spring-boot-maven-plugin + + + + org.projectlombok + lombok + + + + + + diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java index f486c4bd..3f01c279 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -8,6 +8,9 @@ @Data public class ConfigProperties { + @Value("${app.timezone}") + private String timeZone; + @Value("${druid.host}") private String druidHost; @@ -25,4 +28,19 @@ public class ConfigProperties { @Value("${spring.datasource.password}") private String postgresDatasourcePassword; + + @Value("${fiscal.event.datasource}") + private String fiscalEventDataSource; + + @Value("${druid.connect.protocol}") + private String druidConnectProtocol; + + @Value("${druid.connect.port}") + private String druidConnectPort; + + @Value("${fiscal.period}") + private String fiscalPeriod; + + @Value("${department.hierarchy.level}") + private String departmentHierarchyLevel; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java index 90082c8f..5c0cdca7 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java @@ -1,10 +1,13 @@ package org.egov.ifix.aggregate.config; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; import in.zapr.druid.druidry.client.DruidClient; import in.zapr.druid.druidry.client.DruidConfiguration; import in.zapr.druid.druidry.client.DruidJerseyClient; import in.zapr.druid.druidry.client.DruidQueryProtocol; import in.zapr.druid.druidry.client.exception.ConnectionException; +import lombok.extern.slf4j.Slf4j; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -12,35 +15,39 @@ import org.springframework.jdbc.datasource.DriverManagerDataSource; import javax.sql.DataSource; +import java.util.TimeZone; + @Configuration +@Slf4j public class FiscalEventConfiguration { @Autowired private ConfigProperties configProperties; + @Bean + public ObjectMapper objectMapper() { + return new ObjectMapper().disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES) + .setTimeZone(TimeZone.getTimeZone(configProperties.getTimeZone())); + } + @Bean public DruidClient getDruidClient() { DruidConfiguration config = DruidConfiguration .builder() - .protocol(DruidQueryProtocol.HTTPS) + .protocol(DruidQueryProtocol.valueOf(configProperties.getDruidConnectProtocol())) + .port(Integer.valueOf(configProperties.getDruidConnectPort())) .host(configProperties.getDruidHost()) .endpoint(configProperties.getDruidEndPoint()) .build(); DruidClient client = new DruidJerseyClient(config); try { - System.out.println("Druid Client : " + client); client.connect(); + log.debug("Druid Client connection: " + client); } catch (ConnectionException e) { - e.printStackTrace(); + log.error("Exception occurred while getting the druid client -{}", e.getStackTrace()); } - //List responses = client.query(query, DruidResponse.class); -// try { -// client.close(); -// } catch (ConnectionException e) { -// e.printStackTrace(); -// } return client; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java new file mode 100644 index 00000000..08651a96 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/model/FiscalEventAggregate.java @@ -0,0 +1,99 @@ +package org.egov.ifix.aggregate.model; + +import lombok.*; + +import java.math.BigDecimal; +import java.math.BigInteger; + +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +@Builder +@ToString +@EqualsAndHashCode +public class FiscalEventAggregate { + private String ver; + private String tenantId; + private String government_id; + private String government_name; + private String type; + private BigDecimal sumAmount; + private String fiscalPeriod; + private BigInteger count; + private String department_id; + private String department_code; + private String department_name; + + private String departmentEntity_id; + private String departmentEntity_code; + private String departmentEntity_name; + private Integer departmentEntity_hierarchyLevel; + + private String departmentEntity_ancestry_0_id; + private String departmentEntity_ancestry_0_code; + private String departmentEntity_ancestry_0_name; + private Integer departmentEntity_ancestry_0_hierarchyLevel; + private String departmentEntity_ancestry_1_id; + private String departmentEntity_ancestry_1_code; + private String departmentEntity_ancestry_1_name; + private Integer departmentEntity_ancestry_1_hierarchyLevel; + private String departmentEntity_ancestry_2_id; + private String departmentEntity_ancestry_2_code; + private String departmentEntity_ancestry_2_name; + private Integer departmentEntity_ancestry_2_hierarchyLevel; + private String departmentEntity_ancestry_3_id; + private String departmentEntity_ancestry_3_code; + private String departmentEntity_ancestry_3_name; + private Integer departmentEntity_ancestry_3_hierarchyLevel; + private String departmentEntity_ancestry_4_id; + private String departmentEntity_ancestry_4_code; + private String departmentEntity_ancestry_4_name; + private Integer departmentEntity_ancestry_4_hierarchyLevel; + private String departmentEntity_ancestry_5_id; + private String departmentEntity_ancestry_5_code; + private String departmentEntity_ancestry_5_name; + private Integer departmentEntity_ancestry_5_hierarchyLevel; + private String departmentEntity_ancestry_6_id; + private String departmentEntity_ancestry_6_code; + private String departmentEntity_ancestry_6_name; + private Integer departmentEntity_ancestry_6_hierarchyLevel; + private String departmentEntity_ancestry_7_id; + private String departmentEntity_ancestry_7_code; + private String departmentEntity_ancestry_7_name; + private Integer departmentEntity_ancestry_7_hierarchyLevel; + private String departmentEntity_ancestry_8_id; + private String departmentEntity_ancestry_8_code; + private String departmentEntity_ancestry_8_name; + private Integer departmentEntity_ancestry_8_hierarchyLevel; + private String departmentEntity_ancestry_9_id; + private String departmentEntity_ancestry_9_code; + private String departmentEntity_ancestry_9_name; + private Integer departmentEntity_ancestry_9_hierarchyLevel; + private String departmentEntity_ancestry_10_id; + private String departmentEntity_ancestry_10_code; + private String departmentEntity_ancestry_10_name; + private Integer departmentEntity_ancestry_10_hierarchyLevel; + private String expenditure_id; + private String expenditure_code; + private String expenditure_name; + private String expenditure_type; + private String project_id; + private String project_code; + private String project_name; + private String coa_id; + private String coa_coaCode; + private String coa_majorHead; + private String coa_majorHeadName; + private String coa_majorHeadType; + private String coa_subMajorHead; + private String coa_subMajorHeadName; + private String coa_minorHead; + private String coa_minorHeadName; + private String coa_subHead; + private String coa_subHeadName; + private String coa_groupHead; + private String coa_groupHeadName; + private String coa_objectHead; + private String coa_objectHeadName; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index 66ba73f4..b1511fdc 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -1,113 +1,234 @@ package org.egov.ifix.aggregate.processor; +import com.fasterxml.jackson.databind.JsonNode; import in.zapr.druid.druidry.aggregator.CountAggregator; import in.zapr.druid.druidry.aggregator.DoubleSumAggregator; import in.zapr.druid.druidry.aggregator.DruidAggregator; -import in.zapr.druid.druidry.aggregator.LongSumAggregator; import in.zapr.druid.druidry.client.DruidClient; import in.zapr.druid.druidry.client.exception.QueryException; import in.zapr.druid.druidry.dataSource.TableDataSource; import in.zapr.druid.druidry.dimension.DefaultDimension; -import in.zapr.druid.druidry.dimension.DimensionSpec; import in.zapr.druid.druidry.dimension.DruidDimension; -import in.zapr.druid.druidry.dimension.SimpleDimension; import in.zapr.druid.druidry.dimension.enums.OutputType; import in.zapr.druid.druidry.granularity.Granularity; import in.zapr.druid.druidry.granularity.PredefinedGranularity; import in.zapr.druid.druidry.granularity.SimpleGranularity; -import in.zapr.druid.druidry.postAggregator.ArithmeticFunction; -import in.zapr.druid.druidry.postAggregator.ArithmeticPostAggregator; -import in.zapr.druid.druidry.postAggregator.DruidPostAggregator; -import in.zapr.druid.druidry.postAggregator.FieldAccessPostAggregator; import in.zapr.druid.druidry.query.DruidQuery; import in.zapr.druid.druidry.query.aggregation.DruidGroupByQuery; -import in.zapr.druid.druidry.query.aggregation.DruidTopNQuery; import in.zapr.druid.druidry.query.config.Interval; -import in.zapr.druid.druidry.topNMetric.SimpleMetric; -import in.zapr.druid.druidry.topNMetric.TopNMetric; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.ifix.aggregate.config.ConfigProperties; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.repository.FiscalEventAggregateRepository; +import org.egov.ifix.aggregate.util.FiscalEventAggregateConstants; +import org.egov.ifix.aggregate.util.FiscalEventAggregateUtil; import org.joda.time.DateTime; import org.joda.time.DateTimeZone; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.List; +import java.util.*; @Component +@Slf4j public class DruidDataQueryProcessor { @Autowired private DruidClient druidClient; + @Autowired + private ConfigProperties configProperties; + + @Autowired + private FiscalEventAggregateUtil aggregateUtil; - //TODO + @Autowired + private FiscalEventAggregateRepository aggregateRepository; + + /** + * Fetch the fiscal event data with total sum amount , count from druid date store + * based on the group of project id, coa id, event type + */ public void fetchFiscalEventFromDruid() { - System.out.println("*********** Druid_client : " + druidClient); + DruidQuery groupByQuery = getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(); + DruidQuery distinctProjectQuery = getDruidQueryForProjectDetails(); + DruidQuery distinctCoaIdQuery = getDruidQueryForCoaDetails(); + + List groupByResponses = null; + List distinctProjectResponses = null; + List distinctCoaIdResponses = null; + try { + groupByResponses = druidClient.query(groupByQuery, Object.class); + distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); + distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); + } catch (QueryException e) { + log.error("Exception occurred while quering the data from druid data store : {}", e.getDruidError()); + } + log.debug("Group by Response : {}", groupByResponses); + if (groupByResponses == null || groupByResponses.isEmpty()) { + log.info("There are no fiscal event data with group by of project id, event type and coa id"); + return; + } + + //Create a map of key as project id and event node details as value + Map projectNodeMap = aggregateUtil.getProjectDetailsMap(distinctProjectResponses); + //Create a map of key as coa id and event node details as value + Map coaNodeMap = aggregateUtil.getCOADetailsMap(distinctCoaIdResponses); + //Get the details by project id and coa id map key and create a final List + List fiscalEventAggregateList = aggregateUtil.getFiscalEventAggregateData(groupByResponses + , projectNodeMap, coaNodeMap + , configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD); + + //pass the list for upsert + if (fiscalEventAggregateList != null && !fiscalEventAggregateList.isEmpty()) { + int[] upsertedRecord = aggregateRepository.upsert(fiscalEventAggregateList); + log.debug("Record -> {} upserted successfully", upsertedRecord); + } + } + - TableDataSource dataSource = new TableDataSource("fiscal-event"); - DateTime startTime = new DateTime(2021, 1, 1, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(2021, 12, 31, 0, 0, 0, DateTimeZone.UTC); + private DruidQuery getDruidQueryForCoaDetails() { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + Map intervalYearMap = aggregateUtil.getIntervalYearMap(); + + DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); Interval interval = new Interval(startTime, endTime); + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); - DruidDimension dimension1 = new DefaultDimension("project.id","project.id", OutputType.STRING); - DruidDimension dimension2 = new DefaultDimension("coa.id","coa.id", OutputType.STRING); - DruidDimension dimension3 = new DefaultDimension("eventType","eventType", OutputType.STRING); - List druidDimensions = new ArrayList<>(); - druidDimensions.add(dimension1); - druidDimensions.add(dimension2); - druidDimensions.add(dimension3); -// SelectorFilter selectorFilter1 = new SelectorFilter("dim1", "some_value"); -// SelectorFilter selectorFilter2 = new SelectorFilter("dim2", "some_other_val"); -// -// AndFilter filter = new AndFilter(Arrays.asList(selectorFilter1, selectorFilter2)); + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("coa.id", "coa.id", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("coa.coaCode", "coa.coaCode", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.groupHead", "coa.groupHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.groupHeadName", "coa.groupHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.majorHead", "coa.majorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.majorHeadName", "coa.majorHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.minorHead", "coa.minorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.minorHeadName", "coa.minorHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.objectHead", "coa.objectHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.objectHeadName", "coa.objectHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subHead", "coa.subHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subHeadName", "coa.subHeadName", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subMajorHead", "coa.subMajorHead", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.subMajorHeadName", "coa.subMajorHeadName", OutputType.STRING)); + +// List aggregators = new ArrayList<>(); +// aggregators.add(new DistinctCountAggregator("coa.id","coa.id")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + .granularity(granularity) + .filter(null) + //.aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } + + private DruidQuery getDruidQueryForProjectDetails() { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + Map intervalYearMap = aggregateUtil.getIntervalYearMap(); - DruidAggregator aggregator1 = new CountAggregator("Count"); - DruidAggregator aggregator2 = new DoubleSumAggregator("amount", "amount"); - List aggregators = new ArrayList<>(); - aggregators.add(aggregator1); - aggregators.add(aggregator2); + DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); -// FieldAccessPostAggregator fieldAccessPostAggregator1 -// = new FieldAccessPostAggregator("some_metric", "some_metric"); -// -// FieldAccessPostAggregator fieldAccessPostAggregator2 -// = new FieldAccessPostAggregator("count", "count"); + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); -// DruidPostAggregator postAggregator = ArithmeticPostAggregator.builder() -// .name("sample_divide") -// .function(ArithmeticFunction.DIVIDE) -// .fields(Arrays.asList(fieldAccessPostAggregator1, fieldAccessPostAggregator2)) -// .build(); + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("project.id", "project.id", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("department.code", "department.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("department.id", "department.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("department.name", "department.name", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("expenditure.code", "expenditure.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.id", "expenditure.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.name", "expenditure.name", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("expenditure.type", "expenditure.type", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("tenantId", "tenantId", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("government.id", "government.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("government.name", "government.name", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("departmentEntity.id", "departmentEntity.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.code", "departmentEntity.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.name", "departmentEntity.name", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.hierarchyLevel", "departmentEntity.hierarchyLevel", OutputType.STRING)); + + druidDimensions.add(new DefaultDimension("project.code", "project.code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("project.name", "project.name", OutputType.STRING)); + +// druidDimensions.add(new DefaultDimension("id", "id", OutputType.STRING)); +// druidDimensions.add(new DefaultDimension("ingestionTime", "ingestionTime", OutputType.LONG)); +// druidDimensions.add(new DefaultDimension("payment", "payment", OutputType.DOUBLE)); +// druidDimensions.add(new DefaultDimension("referenceId", "referenceId", OutputType.STRING)); +// druidDimensions.add(new DefaultDimension("receipt", "receipt", OutputType.DOUBLE)); +// druidDimensions.add(new DefaultDimension("eventId", "eventId", OutputType.STRING)); +// druidDimensions.add(new DefaultDimension("eventType", "eventType", OutputType.STRING)); +// druidDimensions.add(new DefaultDimension("fromBillingPeriod", "fromBillingPeriod", OutputType.LONG)); +// druidDimensions.add(new DefaultDimension("toBillingPeriod", "toBillingPeriod", OutputType.LONG)); +// druidDimensions.add(new DefaultDimension("bill", "bill", OutputType.DOUBLE)); +// druidDimensions.add(new DefaultDimension("demand", "demand", OutputType.DOUBLE)); +// druidDimensions.add(new DefaultDimension("version", "version", OutputType.STRING)); + + int hierarchyLevel = FiscalEventAggregateConstants.DEFAULT_HIERARCHY_LEVEL; + if (StringUtils.isNotBlank(configProperties.getDepartmentHierarchyLevel())) { + hierarchyLevel = Integer.parseInt(configProperties.getDepartmentHierarchyLevel()); + } + + for (int i = 0; i <= hierarchyLevel; i++) { + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].code", "departmentEntity.ancestry[" + i + "].code", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].hierarchyLevel", "departmentEntity.ancestry[" + i + "].hierarchyLevel", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].id", "departmentEntity.ancestry[" + i + "].id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].name", "departmentEntity.ancestry[" + i + "].name", OutputType.STRING)); + } + +// List aggregators = new ArrayList<>(); +// aggregators.add(new DistinctCountAggregator("project.id","project.id")); +// aggregators.add(new DoubleSumAggregator("amount", "amount")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(druidDimensions) + .granularity(granularity) + .filter(null) + //.aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); + } + private DruidGroupByQuery getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType() { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + Map intervalYearMap = aggregateUtil.getIntervalYearMap(); + DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + List druidDimensions = new ArrayList<>(); + druidDimensions.add(new DefaultDimension("project.id", "project.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("coa.id", "coa.id", OutputType.STRING)); + druidDimensions.add(new DefaultDimension("eventType", "eventType", OutputType.STRING)); - TopNMetric metric = new SimpleMetric("count"); + List aggregators = new ArrayList<>(); + aggregators.add(new CountAggregator("Count")); + aggregators.add(new DoubleSumAggregator("amount", "amount")); - DruidQuery query = DruidGroupByQuery.builder() + return (DruidGroupByQuery.builder() .dataSource(dataSource) .dimensions(druidDimensions) - //.threshold(5) - // .topNMetric(metric) .granularity(granularity) .filter(null) .aggregators(aggregators) - // .postAggregators(Collections.singletonList(postAggregator)) .intervals(Collections.singletonList(interval)) - .build(); -// String responses = null; -// try { -// responses = druidClient.query(query); -// } catch (QueryException e) { -// e.printStackTrace(); -// } -// -// System.out.println("Response : "+responses); - + .build()); } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java new file mode 100644 index 00000000..0382069f --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java @@ -0,0 +1,25 @@ +package org.egov.ifix.aggregate.repository; + +import lombok.extern.slf4j.Slf4j; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.repository.mapper.FiscalEventAggregateQuery; +import org.egov.ifix.aggregate.repository.mapper.FiscalEventAggregatedDataMapper; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@Slf4j +public class FiscalEventAggregateRepository { + + @Autowired + private JdbcTemplate jdbcTemplate; + + + public int[] upsert(List fiscalEventAggregates){ + return (jdbcTemplate.batchUpdate(FiscalEventAggregateQuery.UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE + , new FiscalEventAggregatedDataMapper(fiscalEventAggregates))); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java new file mode 100644 index 00000000..cba86e54 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java @@ -0,0 +1,81 @@ +package org.egov.ifix.aggregate.repository.mapper; + + +import org.springframework.stereotype.Component; + +@Component +public class FiscalEventAggregateQuery { + + public static final String UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + + "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + + "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + + "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + + "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + + "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ + "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ + "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + + "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + + "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + + "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + + "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + + "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + + "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + + "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + + "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + + "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + + "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + + "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + + "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel,departmentEntity_id,departmentEntity_code," + + "departmentEntity_name,departmentEntity_hierarchyLevel) " + + "VALUES" + + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + + "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, ?,?,?,?) " + + "ON CONFLICT(project_id,coa_id,type,fiscalPeriod) " + + "DO UPDATE " + + "SET " + + "ver=?,tenantId=?,government_id=?,government_name=?,sumAmount=?,count=?,department_id=?," + + "department_code=?,department_name=?,departmentEntity_ancestry_0_id=?," + + "expenditure_id=?,expenditure_code=?,expenditure_name=?,expenditure_type=?,project_code=?,project_name=?," + + "coa_coaCode=?,coa_majorHead=?,coa_majorHeadName=?,coa_majorHeadType=?,coa_subMajorHead=?,coa_subMajorHeadName=?,coa_minorHead=?," + + "coa_minorHeadName=?,coa_subHead=?,coa_subHeadName=?,coa_groupHead=?,coa_groupHeadName=?,coa_objectHead=?,coa_objectHeadName=?, " + + "departmentEntity_ancestry_0_code=?," + + "departmentEntity_ancestry_0_name=?,departmentEntity_ancestry_0_hierarchyLevel=?,departmentEntity_ancestry_1_id=?," + + "departmentEntity_ancestry_1_code=?,departmentEntity_ancestry_1_name=?,departmentEntity_ancestry_1_hierarchyLevel=?," + + "departmentEntity_ancestry_2_id=?,departmentEntity_ancestry_2_code=?,departmentEntity_ancestry_2_name=?," + + "departmentEntity_ancestry_2_hierarchyLevel=?,departmentEntity_ancestry_3_id=?,departmentEntity_ancestry_3_code=?," + + "departmentEntity_ancestry_3_name=?,departmentEntity_ancestry_3_hierarchyLevel=?,departmentEntity_ancestry_4_id=?," + + "departmentEntity_ancestry_4_code=?,departmentEntity_ancestry_4_name=?,departmentEntity_ancestry_4_hierarchyLevel=?," + + "departmentEntity_ancestry_5_id=?,departmentEntity_ancestry_5_code=?,departmentEntity_ancestry_5_name=?," + + "departmentEntity_ancestry_5_hierarchyLevel=?,departmentEntity_ancestry_6_id=?,departmentEntity_ancestry_6_code=?," + + "departmentEntity_ancestry_6_name=?,departmentEntity_ancestry_6_hierarchyLevel=?,departmentEntity_ancestry_7_id=?," + + "departmentEntity_ancestry_7_code=?,departmentEntity_ancestry_7_name=?,departmentEntity_ancestry_7_hierarchyLevel=?," + + "departmentEntity_ancestry_8_id=?,departmentEntity_ancestry_8_code=?,departmentEntity_ancestry_8_name=?," + + "departmentEntity_ancestry_8_hierarchyLevel=?,departmentEntity_ancestry_9_id=?,departmentEntity_ancestry_9_code=?," + + "departmentEntity_ancestry_9_name=?,departmentEntity_ancestry_9_hierarchyLevel=?,departmentEntity_ancestry_10_id=?," + + "departmentEntity_ancestry_10_code=?,departmentEntity_ancestry_10_name=?,departmentEntity_ancestry_10_hierarchyLevel=?," + + "departmentEntity_id=?,departmentEntity_code=?,departmentEntity_name=?,departmentEntity_hierarchyLevel=?;"; + + public static final String INSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + + "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + + "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + + "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + + "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + + "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ + "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ + "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + + "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + + "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + + "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + + "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + + "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + + "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + + "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + + "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + + "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + + "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + + "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + + "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel) " + + "VALUES" + + "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + + "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ;" ; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java new file mode 100644 index 00000000..c7ace02c --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java @@ -0,0 +1,241 @@ +package org.egov.ifix.aggregate.repository.mapper; + +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.springframework.jdbc.core.BatchPreparedStatementSetter; +import org.springframework.stereotype.Component; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.List; + +@Component +public class FiscalEventAggregatedDataMapper implements BatchPreparedStatementSetter { + + private List fiscalEventAggregates = null; + + public FiscalEventAggregatedDataMapper(List fiscalEventAggregates) { + this.fiscalEventAggregates = fiscalEventAggregates; + } + + @Override + public void setValues(PreparedStatement ps, int i) throws SQLException { + FiscalEventAggregate fiscalEventAggregate = fiscalEventAggregates.get(i); + + ps.setString(1, fiscalEventAggregate.getVer()); + ps.setString(2, fiscalEventAggregate.getTenantId()); + ps.setString(3, fiscalEventAggregate.getGovernment_id()); + ps.setString(4, fiscalEventAggregate.getGovernment_name()); + ps.setString(5, fiscalEventAggregate.getType()); + ps.setBigDecimal(6, fiscalEventAggregate.getSumAmount()); + ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); + ps.setLong(8, Long.parseLong(fiscalEventAggregate.getCount().toString()));// + ps.setString(9, fiscalEventAggregate.getDepartment_id()); + ps.setString(10, fiscalEventAggregate.getDepartment_code()); + ps.setString(11, fiscalEventAggregate.getDepartment_name()); + + ps.setString(12, fiscalEventAggregate.getExpenditure_id()); + ps.setString(13, fiscalEventAggregate.getExpenditure_code()); + ps.setString(14, fiscalEventAggregate.getExpenditure_name()); + ps.setString(15, fiscalEventAggregate.getExpenditure_type()); + + ps.setString(16, fiscalEventAggregate.getProject_id()); + ps.setString(17, fiscalEventAggregate.getProject_code()); + ps.setString(18, fiscalEventAggregate.getProject_name()); + + ps.setString(19, fiscalEventAggregate.getCoa_id()); + ps.setString(20, fiscalEventAggregate.getCoa_coaCode()); + ps.setString(21, fiscalEventAggregate.getCoa_majorHead()); + ps.setString(22, fiscalEventAggregate.getCoa_majorHeadName()); + ps.setString(23, fiscalEventAggregate.getCoa_majorHeadType()); + ps.setString(24, fiscalEventAggregate.getCoa_subMajorHead()); + ps.setString(25, fiscalEventAggregate.getCoa_subMajorHeadName()); + ps.setString(26, fiscalEventAggregate.getCoa_minorHead()); + ps.setString(27, fiscalEventAggregate.getCoa_minorHeadName()); + ps.setString(28, fiscalEventAggregate.getCoa_subHead()); + ps.setString(29, fiscalEventAggregate.getCoa_subHeadName()); + ps.setString(30, fiscalEventAggregate.getCoa_groupHead()); + ps.setString(31, fiscalEventAggregate.getCoa_groupHeadName()); + ps.setString(32, fiscalEventAggregate.getCoa_objectHead()); + ps.setString(33, fiscalEventAggregate.getCoa_objectHeadName()); + + ps.setString(34, fiscalEventAggregate.getDepartmentEntity_ancestry_0_id()); + ps.setString(35, fiscalEventAggregate.getDepartmentEntity_ancestry_0_code()); + ps.setString(36, fiscalEventAggregate.getDepartmentEntity_ancestry_0_name()); + ps.setInt(37, fiscalEventAggregate.getDepartmentEntity_ancestry_0_hierarchyLevel()); + + + ps.setString(38, fiscalEventAggregate.getDepartmentEntity_ancestry_1_id()); + ps.setString(39, fiscalEventAggregate.getDepartmentEntity_ancestry_1_code()); + ps.setString(40, fiscalEventAggregate.getDepartmentEntity_ancestry_1_name()); + ps.setInt(41, fiscalEventAggregate.getDepartmentEntity_ancestry_1_hierarchyLevel()); + + ps.setString(42, fiscalEventAggregate.getDepartmentEntity_ancestry_2_id()); + ps.setString(43, fiscalEventAggregate.getDepartmentEntity_ancestry_2_code()); + ps.setString(44, fiscalEventAggregate.getDepartmentEntity_ancestry_2_name()); + ps.setInt(45, fiscalEventAggregate.getDepartmentEntity_ancestry_2_hierarchyLevel()); + + ps.setString(46, fiscalEventAggregate.getDepartmentEntity_ancestry_3_id()); + ps.setString(47, fiscalEventAggregate.getDepartmentEntity_ancestry_3_code()); + ps.setString(48, fiscalEventAggregate.getDepartmentEntity_ancestry_3_name()); + ps.setInt(49, fiscalEventAggregate.getDepartmentEntity_ancestry_3_hierarchyLevel()); + + ps.setString(50, fiscalEventAggregate.getDepartmentEntity_ancestry_4_id()); + ps.setString(51, fiscalEventAggregate.getDepartmentEntity_ancestry_4_code()); + ps.setString(52, fiscalEventAggregate.getDepartmentEntity_ancestry_4_name()); + ps.setInt(53, fiscalEventAggregate.getDepartmentEntity_ancestry_4_hierarchyLevel()); + + ps.setString(54, fiscalEventAggregate.getDepartmentEntity_ancestry_5_id()); + ps.setString(55, fiscalEventAggregate.getDepartmentEntity_ancestry_5_code()); + ps.setString(56, fiscalEventAggregate.getDepartmentEntity_ancestry_5_name()); + ps.setInt(57, fiscalEventAggregate.getDepartmentEntity_ancestry_5_hierarchyLevel()); + + ps.setString(58, fiscalEventAggregate.getDepartmentEntity_ancestry_6_id()); + ps.setString(59, fiscalEventAggregate.getDepartmentEntity_ancestry_6_code()); + ps.setString(60, fiscalEventAggregate.getDepartmentEntity_ancestry_6_name()); + ps.setInt(61, fiscalEventAggregate.getDepartmentEntity_ancestry_6_hierarchyLevel()); + + ps.setString(62, fiscalEventAggregate.getDepartmentEntity_ancestry_7_id()); + ps.setString(63, fiscalEventAggregate.getDepartmentEntity_ancestry_7_code()); + ps.setString(64, fiscalEventAggregate.getDepartmentEntity_ancestry_7_name()); + ps.setInt(65, fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() + : 7); + + ps.setString(66, fiscalEventAggregate.getDepartmentEntity_ancestry_8_id()); + ps.setString(67, fiscalEventAggregate.getDepartmentEntity_ancestry_8_code()); + ps.setString(68, fiscalEventAggregate.getDepartmentEntity_ancestry_8_name()); + ps.setInt(69, fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() : 8); + + ps.setString(70, fiscalEventAggregate.getDepartmentEntity_ancestry_9_id()); + ps.setString(71, fiscalEventAggregate.getDepartmentEntity_ancestry_9_code()); + ps.setString(72, fiscalEventAggregate.getDepartmentEntity_ancestry_9_name()); + ps.setInt(73, fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() : 9); + + ps.setString(74, fiscalEventAggregate.getDepartmentEntity_ancestry_10_id()); + ps.setString(75, fiscalEventAggregate.getDepartmentEntity_ancestry_10_code()); + ps.setString(76, fiscalEventAggregate.getDepartmentEntity_ancestry_10_name()); + ps.setInt(77, fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() : 10); + + + ps.setString(78, fiscalEventAggregate.getDepartmentEntity_id()); + ps.setString(79, fiscalEventAggregate.getDepartmentEntity_code()); + ps.setString(80, fiscalEventAggregate.getDepartmentEntity_name()); + ps.setInt(81, fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() : 0); + + + + //Update on conflict + ps.setString(82, fiscalEventAggregate.getVer()); + ps.setString(83, fiscalEventAggregate.getTenantId()); + ps.setString(84, fiscalEventAggregate.getGovernment_id()); + ps.setString(85, fiscalEventAggregate.getGovernment_name()); + //ps.setString(5, fiscalEventAggregate.getEventType()); + ps.setBigDecimal(86, fiscalEventAggregate.getSumAmount()); + //ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); + ps.setLong(87, Long.parseLong(fiscalEventAggregate.getCount().toString()));// + ps.setString(88, fiscalEventAggregate.getDepartment_id()); + ps.setString(89, fiscalEventAggregate.getDepartment_code()); + ps.setString(90, fiscalEventAggregate.getDepartment_name()); + + ps.setString(91, fiscalEventAggregate.getExpenditure_id()); + ps.setString(92, fiscalEventAggregate.getExpenditure_code()); + ps.setString(93, fiscalEventAggregate.getExpenditure_name()); + ps.setString(94, fiscalEventAggregate.getExpenditure_type()); + + //ps.setString(91, fiscalEventAggregate.getProject_id()); + ps.setString(95, fiscalEventAggregate.getProject_code()); + ps.setString(96, fiscalEventAggregate.getProject_name()); + + //ps.setString(19, fiscalEventAggregate.getCoa_id()); + ps.setString(97, fiscalEventAggregate.getCoa_coaCode()); + ps.setString(98, fiscalEventAggregate.getCoa_majorHead()); + ps.setString(99, fiscalEventAggregate.getCoa_majorHeadName()); + ps.setString(100, fiscalEventAggregate.getCoa_majorHeadType()); + ps.setString(101, fiscalEventAggregate.getCoa_subMajorHead()); + ps.setString(102, fiscalEventAggregate.getCoa_subMajorHeadName()); + ps.setString(103, fiscalEventAggregate.getCoa_minorHead()); + ps.setString(104, fiscalEventAggregate.getCoa_minorHeadName()); + ps.setString(105, fiscalEventAggregate.getCoa_subHead()); + ps.setString(106, fiscalEventAggregate.getCoa_subHeadName()); + ps.setString(107, fiscalEventAggregate.getCoa_groupHead()); + ps.setString(108, fiscalEventAggregate.getCoa_groupHeadName()); + ps.setString(109, fiscalEventAggregate.getCoa_objectHead()); + ps.setString(110, fiscalEventAggregate.getCoa_objectHeadName()); + + ps.setString(111, fiscalEventAggregate.getDepartmentEntity_ancestry_0_id()); + ps.setString(112, fiscalEventAggregate.getDepartmentEntity_ancestry_0_code()); + ps.setString(113, fiscalEventAggregate.getDepartmentEntity_ancestry_0_name()); + ps.setInt(114, fiscalEventAggregate.getDepartmentEntity_ancestry_0_hierarchyLevel()); + + + ps.setString(115, fiscalEventAggregate.getDepartmentEntity_ancestry_1_id()); + ps.setString(116, fiscalEventAggregate.getDepartmentEntity_ancestry_1_code()); + ps.setString(117, fiscalEventAggregate.getDepartmentEntity_ancestry_1_name()); + ps.setInt(118, fiscalEventAggregate.getDepartmentEntity_ancestry_1_hierarchyLevel()); + + ps.setString(119, fiscalEventAggregate.getDepartmentEntity_ancestry_2_id()); + ps.setString(120, fiscalEventAggregate.getDepartmentEntity_ancestry_2_code()); + ps.setString(121, fiscalEventAggregate.getDepartmentEntity_ancestry_2_name()); + ps.setInt(122, fiscalEventAggregate.getDepartmentEntity_ancestry_2_hierarchyLevel()); + + ps.setString(123, fiscalEventAggregate.getDepartmentEntity_ancestry_3_id()); + ps.setString(124, fiscalEventAggregate.getDepartmentEntity_ancestry_3_code()); + ps.setString(125, fiscalEventAggregate.getDepartmentEntity_ancestry_3_name()); + ps.setInt(126, fiscalEventAggregate.getDepartmentEntity_ancestry_3_hierarchyLevel()); + + ps.setString(127, fiscalEventAggregate.getDepartmentEntity_ancestry_4_id()); + ps.setString(128, fiscalEventAggregate.getDepartmentEntity_ancestry_4_code()); + ps.setString(129, fiscalEventAggregate.getDepartmentEntity_ancestry_4_name()); + ps.setInt(130, fiscalEventAggregate.getDepartmentEntity_ancestry_4_hierarchyLevel()); + + ps.setString(131, fiscalEventAggregate.getDepartmentEntity_ancestry_5_id()); + ps.setString(132, fiscalEventAggregate.getDepartmentEntity_ancestry_5_code()); + ps.setString(133, fiscalEventAggregate.getDepartmentEntity_ancestry_5_name()); + ps.setInt(134, fiscalEventAggregate.getDepartmentEntity_ancestry_5_hierarchyLevel()); + + ps.setString(135, fiscalEventAggregate.getDepartmentEntity_ancestry_6_id()); + ps.setString(136, fiscalEventAggregate.getDepartmentEntity_ancestry_6_code()); + ps.setString(137, fiscalEventAggregate.getDepartmentEntity_ancestry_6_name()); + ps.setInt(138, fiscalEventAggregate.getDepartmentEntity_ancestry_6_hierarchyLevel()); + + ps.setString(139, fiscalEventAggregate.getDepartmentEntity_ancestry_7_id()); + ps.setString(140, fiscalEventAggregate.getDepartmentEntity_ancestry_7_code()); + ps.setString(141, fiscalEventAggregate.getDepartmentEntity_ancestry_7_name()); + ps.setInt(142, fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() + : 7); + + ps.setString(143, fiscalEventAggregate.getDepartmentEntity_ancestry_8_id()); + ps.setString(144, fiscalEventAggregate.getDepartmentEntity_ancestry_8_code()); + ps.setString(145, fiscalEventAggregate.getDepartmentEntity_ancestry_8_name()); + ps.setInt(146, fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() : 8); + + ps.setString(147, fiscalEventAggregate.getDepartmentEntity_ancestry_9_id()); + ps.setString(148, fiscalEventAggregate.getDepartmentEntity_ancestry_9_code()); + ps.setString(149, fiscalEventAggregate.getDepartmentEntity_ancestry_9_name()); + ps.setInt(150, fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() : 9); + + ps.setString(151, fiscalEventAggregate.getDepartmentEntity_ancestry_10_id()); + ps.setString(152, fiscalEventAggregate.getDepartmentEntity_ancestry_10_code()); + ps.setString(153, fiscalEventAggregate.getDepartmentEntity_ancestry_10_name()); + ps.setInt(154, fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() : 10); + + ps.setString(155, fiscalEventAggregate.getDepartmentEntity_id()); + ps.setString(156, fiscalEventAggregate.getDepartmentEntity_code()); + ps.setString(157, fiscalEventAggregate.getDepartmentEntity_name()); + ps.setInt(158, fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() != null + ? fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() : 0); + } + + @Override + public int getBatchSize() { + return fiscalEventAggregates.size(); + } +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java new file mode 100644 index 00000000..463c5bb9 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -0,0 +1,12 @@ +package org.egov.ifix.aggregate.util; + +public class FiscalEventAggregateConstants { + + private FiscalEventAggregateConstants(){} + + public static final String DEFAULT_FISCAL_PERIOD = "2021-22"; + public static final String START_YEAR = "START_YEAR"; + public static final String END_YEAR = "END_YEAR"; + public static final int DEFAULT_HIERARCHY_LEVEL = 6; + public static final String VER = "0.1.0"; +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java new file mode 100644 index 00000000..6df77fe6 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java @@ -0,0 +1,312 @@ +package org.egov.ifix.aggregate.util; + +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.egov.ifix.aggregate.config.ConfigProperties; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.*; + +@Slf4j +@Component +public class FiscalEventAggregateUtil { + + @Autowired + private ObjectMapper objectMapper; + + @Autowired + private ConfigProperties configProperties; + + /** + * @param distinctProjectResponses + * @return + */ + public Map getProjectDetailsMap(List distinctProjectResponses) { + JsonNode responseJsonNode = objectMapper.convertValue(distinctProjectResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map projectNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("project.id") != null) { + projectNodeMap.put(eventNode.get("project.id").asText(), eventNode); + } + } + } + return projectNodeMap; + } + + /** + * @param distinctCoaIdResponses + * @return + */ + public Map getCOADetailsMap(List distinctCoaIdResponses) { + JsonNode responseJsonNode = objectMapper.convertValue(distinctCoaIdResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map coaNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("coa.id") != null) { + coaNodeMap.put(eventNode.get("coa.id").asText(), eventNode); + } + } + } + return coaNodeMap; + } + + public Map getIntervalYearMap() { + Map intervalYearMap = new HashMap<>(); + + String[] defaultFiscalPeriodArr = (FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD).split("-"); + String prefixYear = defaultFiscalPeriodArr[0].substring(0, 2); + int startYear = Integer.parseInt(defaultFiscalPeriodArr[0]); + int endYear = Integer.parseInt(prefixYear.concat(defaultFiscalPeriodArr[1])); + if (StringUtils.isNotBlank(configProperties.getFiscalPeriod())) { + String[] strArr = configProperties.getFiscalPeriod().split("-"); + prefixYear = strArr[0].substring(0, 2); + startYear = Integer.parseInt(strArr[0]); + endYear = Integer.parseInt(strArr[1] != null && strArr[1].length() == 4 ? strArr[1] : prefixYear.concat(strArr[1])); + } + intervalYearMap.put(FiscalEventAggregateConstants.START_YEAR, startYear); + intervalYearMap.put(FiscalEventAggregateConstants.END_YEAR, endYear); + return intervalYearMap; + } + + /** + * @param groupByResponses + * @param projectNodeMap + * @param coaNodeMap + * @param fiscalPeriod + * @return + */ + public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap, String fiscalPeriod) { + List fiscalEventAggregateList = new ArrayList<>(); + JsonNode responseJsonNode = objectMapper.convertValue(groupByResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + FiscalEventAggregate eventAggregate = new FiscalEventAggregate(); + + BigDecimal amount = eventNode.get("amount") != null ? eventNode.get("amount").decimalValue() : null; + BigInteger count = eventNode.get("Count") != null ? eventNode.get("Count").bigIntegerValue() : null; + String projectId = eventNode.get("project.id") != null ? eventNode.get("project.id").asText() : null; + String coaId = eventNode.get("coa.id") != null ? eventNode.get("coa.id").asText() : null; + String eventType = eventNode.get("eventType") != null ? eventNode.get("eventType").asText() : null; + + eventAggregate.setProject_id(projectId); + eventAggregate.setSumAmount(amount); + eventAggregate.setCount(count); + eventAggregate.setCoa_id(coaId); + eventAggregate.setType(eventType); + + eventAggregate.setVer(FiscalEventAggregateConstants.VER); + eventAggregate.setFiscalPeriod(fiscalPeriod); + //set the project details to fiscal event aggregate + setProjectDetailsToFiscalEventAggregate(projectNodeMap, eventAggregate, projectId); + + //set the coa details to fiscal event aggregate + setCoaDetailsToFiscalEventAggregate(coaNodeMap, eventAggregate, coaId); + + //TODO : push to kafka + fiscalEventAggregateList.add(eventAggregate); + } + } + return fiscalEventAggregateList; + } + + private void setCoaDetailsToFiscalEventAggregate(Map coaNodeMap, FiscalEventAggregate eventAggregate, String coaId) { + if (coaNodeMap.containsKey(coaId)) { + JsonNode coaEventNode = coaNodeMap.get(coaId); + if (coaEventNode != null && !coaEventNode.isEmpty()) { + eventAggregate.setCoa_coaCode(coaEventNode.get("coa.coaCode") != null + ? coaEventNode.get("coa.coaCode").asText() : null); + eventAggregate.setCoa_groupHead(coaEventNode.get("coa.groupHead") != null + ? coaEventNode.get("coa.groupHead").asText() : null); + eventAggregate.setCoa_groupHeadName(coaEventNode.get("coa.groupHeadName") != null + ? coaEventNode.get("coa.groupHeadName").asText() : null); + eventAggregate.setCoa_majorHead(coaEventNode.get("coa.majorHead") != null + ? coaEventNode.get("coa.majorHead").asText() : null); + eventAggregate.setCoa_majorHeadName(coaEventNode.get("coa.majorHeadName") != null + ? coaEventNode.get("coa.majorHeadName").asText() : null); + + eventAggregate.setCoa_minorHead(coaEventNode.get("coa.minorHead") != null + ? coaEventNode.get("coa.minorHead").asText() : null); + eventAggregate.setCoa_minorHeadName(coaEventNode.get("coa.minorHeadName") != null + ? coaEventNode.get("coa.minorHeadName").asText() : null); + eventAggregate.setCoa_objectHead(coaEventNode.get("coa.objectHead") != null + ? coaEventNode.get("coa.objectHead").asText() : null); + eventAggregate.setCoa_objectHeadName(coaEventNode.get("coa.objectHeadName") != null + ? coaEventNode.get("coa.objectHeadName").asText() : null); + + eventAggregate.setCoa_subHead(coaEventNode.get("coa.subHead") != null + ? coaEventNode.get("coa.subHead").asText() : null); + eventAggregate.setCoa_subHeadName(coaEventNode.get("coa.subHeadName") != null + ? coaEventNode.get("coa.subHeadName").asText() : null); + eventAggregate.setCoa_subMajorHead(coaEventNode.get("coa.subMajorHead") != null + ? coaEventNode.get("coa.subMajorHead").asText() : null); + eventAggregate.setCoa_subMajorHeadName(coaEventNode.get("coa.subMajorHeadName") != null + ? coaEventNode.get("coa.subMajorHeadName").asText() : null); + + } + } + } + + private void setProjectDetailsToFiscalEventAggregate(Map projectNodeMap, FiscalEventAggregate eventAggregate, String projectId) { + if (projectNodeMap.containsKey(projectId)) { + JsonNode projectEventNode = projectNodeMap.get(projectId); + if (projectEventNode != null && !projectEventNode.isEmpty()) { + eventAggregate.setDepartment_code(projectEventNode.get("department.code") != null + ? projectEventNode.get("department.code").asText() : null); + eventAggregate.setDepartment_id(projectEventNode.get("department.id") != null + ? projectEventNode.get("department.id").asText() : null); + eventAggregate.setDepartment_name(projectEventNode.get("department.name") != null + ? projectEventNode.get("department.name").asText() : null); + + eventAggregate.setDepartmentEntity_code(projectEventNode.get("departmentEntity.code") != null + ? projectEventNode.get("departmentEntity.code").asText() : null); + eventAggregate.setDepartmentEntity_hierarchyLevel(projectEventNode.get("departmentEntity.hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_id(projectEventNode.get("departmentEntity.id") != null + ? projectEventNode.get("departmentEntity.id").asText() : null); + eventAggregate.setDepartmentEntity_name(projectEventNode.get("departmentEntity.name") != null + ? projectEventNode.get("departmentEntity.name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_0_code(projectEventNode.get("departmentEntity.ancestry[0].code") != null + ? projectEventNode.get("departmentEntity.ancestry[0].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_0_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[0].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[0].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_0_id(projectEventNode.get("departmentEntity.ancestry[0].id") != null + ? projectEventNode.get("departmentEntity.ancestry[0].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_0_name(projectEventNode.get("departmentEntity.ancestry[0].name") != null + ? projectEventNode.get("departmentEntity.ancestry[0].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_1_code(projectEventNode.get("departmentEntity.ancestry[1].code") != null + ? projectEventNode.get("departmentEntity.ancestry[1].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_1_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[1].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[1].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_1_id(projectEventNode.get("departmentEntity.ancestry[1].id") != null + ? projectEventNode.get("departmentEntity.ancestry[1].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_1_name(projectEventNode.get("departmentEntity.ancestry[1].name") != null + ? projectEventNode.get("departmentEntity.ancestry[1].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_2_code(projectEventNode.get("departmentEntity.ancestry[2].code") != null + ? projectEventNode.get("departmentEntity.ancestry[2].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_2_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[2].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[2].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_2_id(projectEventNode.get("departmentEntity.ancestry[2].id") != null + ? projectEventNode.get("departmentEntity.ancestry[2].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_2_name(projectEventNode.get("departmentEntity.ancestry[2].name") != null + ? projectEventNode.get("departmentEntity.ancestry[2].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_3_code(projectEventNode.get("departmentEntity.ancestry[3].code") != null + ? projectEventNode.get("departmentEntity.ancestry[3].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_3_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[3].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[3].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_3_id(projectEventNode.get("departmentEntity.ancestry[3].id") != null + ? projectEventNode.get("departmentEntity.ancestry[3].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_3_name(projectEventNode.get("departmentEntity.ancestry[3].name") != null + ? projectEventNode.get("departmentEntity.ancestry[3].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_4_code(projectEventNode.get("departmentEntity.ancestry[4].code") != null + ? projectEventNode.get("departmentEntity.ancestry[4].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_4_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[4].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[4].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_4_id(projectEventNode.get("departmentEntity.ancestry[4].id") != null + ? projectEventNode.get("departmentEntity.ancestry[4].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_4_name(projectEventNode.get("departmentEntity.ancestry[4].name") != null + ? projectEventNode.get("departmentEntity.ancestry[4].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_5_code(projectEventNode.get("departmentEntity.ancestry[5].code") != null + ? projectEventNode.get("departmentEntity.ancestry[5].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_5_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[5].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[5].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_5_id(projectEventNode.get("departmentEntity.ancestry[5].id") != null + ? projectEventNode.get("departmentEntity.ancestry[5].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_5_name(projectEventNode.get("departmentEntity.ancestry[5].name") != null + ? projectEventNode.get("departmentEntity.ancestry[5].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_6_code(projectEventNode.get("departmentEntity.ancestry[6].code") != null + ? projectEventNode.get("departmentEntity.ancestry[6].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_6_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[6].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[6].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_6_id(projectEventNode.get("departmentEntity.ancestry[6].id") != null + ? projectEventNode.get("departmentEntity.ancestry[6].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_6_name(projectEventNode.get("departmentEntity.ancestry[6].name") != null + ? projectEventNode.get("departmentEntity.ancestry[6].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_7_code(projectEventNode.get("departmentEntity.ancestry[7].code") != null + ? projectEventNode.get("departmentEntity.ancestry[7].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_7_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[7].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[7].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_7_id(projectEventNode.get("departmentEntity.ancestry[7].id") != null + ? projectEventNode.get("departmentEntity.ancestry[7].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_7_name(projectEventNode.get("departmentEntity.ancestry[7].name") != null + ? projectEventNode.get("departmentEntity.ancestry[7].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_8_code(projectEventNode.get("departmentEntity.ancestry[8].code") != null + ? projectEventNode.get("departmentEntity.ancestry[8].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_8_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[8].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[8].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_8_id(projectEventNode.get("departmentEntity.ancestry[8].id") != null + ? projectEventNode.get("departmentEntity.ancestry[8].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_8_name(projectEventNode.get("departmentEntity.ancestry[8].name") != null + ? projectEventNode.get("departmentEntity.ancestry[8].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_9_code(projectEventNode.get("departmentEntity.ancestry[9].code") != null + ? projectEventNode.get("departmentEntity.ancestry[9].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_9_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[9].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[9].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_9_id(projectEventNode.get("departmentEntity.ancestry[9].id") != null + ? projectEventNode.get("departmentEntity.ancestry[9].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_9_name(projectEventNode.get("departmentEntity.ancestry[9].name") != null + ? projectEventNode.get("departmentEntity.ancestry[9].name").asText() : null); + + eventAggregate.setDepartmentEntity_ancestry_10_code(projectEventNode.get("departmentEntity.ancestry[10].code") != null + ? projectEventNode.get("departmentEntity.ancestry[10].code").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_10_hierarchyLevel(projectEventNode.get("departmentEntity.ancestry[10].hierarchyLevel") != null + ? projectEventNode.get("departmentEntity.ancestry[10].hierarchyLevel").asInt() : null); + eventAggregate.setDepartmentEntity_ancestry_10_id(projectEventNode.get("departmentEntity.ancestry[10].id") != null + ? projectEventNode.get("departmentEntity.ancestry[10].id").asText() : null); + eventAggregate.setDepartmentEntity_ancestry_10_name(projectEventNode.get("departmentEntity.ancestry[10].name") != null + ? projectEventNode.get("departmentEntity.ancestry[10].name").asText() : null); + + eventAggregate.setExpenditure_code(projectEventNode.get("expenditure.code") != null + ? projectEventNode.get("expenditure.code").asText() : null); + eventAggregate.setExpenditure_id(projectEventNode.get("expenditure.id") != null + ? projectEventNode.get("expenditure.id").asText() : null); + eventAggregate.setExpenditure_name(projectEventNode.get("expenditure.name") != null + ? projectEventNode.get("expenditure.name").asText() : null); + eventAggregate.setExpenditure_type(projectEventNode.get("expenditure.type") != null + ? projectEventNode.get("expenditure.type").asText() : null); + + eventAggregate.setGovernment_id(projectEventNode.get("government.id") != null + ? projectEventNode.get("government.id").asText() : null); + eventAggregate.setGovernment_name(projectEventNode.get("government.name") != null + ? projectEventNode.get("government.name").asText() : null); + + eventAggregate.setTenantId(projectEventNode.get("tenantId") != null + ? projectEventNode.get("tenantId").asText() : null); + + eventAggregate.setProject_code(projectEventNode.get("project.code") != null + ? projectEventNode.get("project.code").asText() : null); + eventAggregate.setProject_name(projectEventNode.get("project.name") != null + ? projectEventNode.get("project.name").asText() : null); + +// eventAggregate.setVer(projectEventNode.get("version") != null +// ? projectEventNode.get("version").asText() : null); + } + } + } + +} diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index a0e0a799..f5528b1a 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -1,8 +1,29 @@ +app.timezone=UTC + +## Postgres config ## spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.url=jdbc:postgresql://localhost:5432/fiscal_event spring.datasource.username=postgres -spring.datasource.password=postgres +spring.datasource.password=root ## Druid Config ## -druid.host=druid-qa.ifix.org.in +druid.host=druid.ifix.org.in druid.endPoint=druid/v2/ +fiscal.event.datasource=fiscal-event +druid.connect.protocol=HTTPS +druid.connect.port=443 + +##flyway config ## +flyway.url=jdbc:postgresql://localhost:5432/fiscal_event +flyway.user=postgres +flyway.password=postgres +flyway.table=public +flyway.baseline-on-migrate=true +flyway.outOfOrder=true +flyway.locations=classpath:/db/migration +flyway.enabled=true + +spring.flyway.baseline-on-migrate = true + +fiscal.period=2021-22 +department.hierarchy.level=6 \ No newline at end of file diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210921173000__fiscal_event_aggregate.sql similarity index 93% rename from reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql rename to reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210921173000__fiscal_event_aggregate.sql index 6be42a66..205917f3 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210914173000__fiscal_event_aggregate.sql +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210921173000__fiscal_event_aggregate.sql @@ -3,16 +3,25 @@ DROP TABLE IF EXISTS fiscal_event_aggregated; CREATE TABLE fiscal_event_aggregated( ver TEXT, id SERIAL, + + sumAmount DECIMAL, + count bigint, + fiscalPeriod TEXT, + + type TEXT, + + project_id TEXT, + tenantId TEXT, government_id TEXT, government_name TEXT, - eventType TEXT, - sumAmount DECIMAL, - fiscalPeriod TEXT, - count bigint, department_id TEXT, department_code TEXT, department_name TEXT, + departmentEntity_code TEXT, + departmentEntity_hierarchyLevel integer, + departmentEntity_id TEXT, + departmentEntity_name TEXT, departmentEntity_ancestry_0_id TEXT, departmentEntity_ancestry_0_code TEXT, departmentEntity_ancestry_0_name TEXT, @@ -61,9 +70,9 @@ CREATE TABLE fiscal_event_aggregated( expenditure_code TEXT, expenditure_name TEXT, expenditure_type TEXT, - project_id TEXT, project_code TEXT, project_name TEXT, + coa_id TEXT, coa_coaCode TEXT, coa_majorHead TEXT, @@ -79,5 +88,7 @@ CREATE TABLE fiscal_event_aggregated( coa_groupHeadName TEXT, coa_objectHead TEXT, coa_objectHeadName TEXT, + + unique(project_id,coa_id,fiscalPeriod,type), PRIMARY KEY (id) ); From f1f4c81bd8e4a57de2edac54754b56ab566b1f1b Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Wed, 22 Sep 2021 11:44:11 +0530 Subject: [PATCH 54/67] review comments --- .../aggregate/config/ConfigProperties.java | 12 ------------ .../config/FiscalEventConfiguration.java | 18 ------------------ .../processor/DruidDataQueryProcessor.java | 10 ++++++++-- 3 files changed, 8 insertions(+), 32 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java index 3f01c279..7a5c8c80 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -17,18 +17,6 @@ public class ConfigProperties { @Value("${druid.endPoint}") private String druidEndPoint; - @Value("${spring.datasource.driver-class-name}") - private String postgresDatasourceDriverClassName; - - @Value("${spring.datasource.url}") - private String postgresDatasourceUrl; - - @Value("${spring.datasource.username}") - private String postgresDatasourceUsername; - - @Value("${spring.datasource.password}") - private String postgresDatasourcePassword; - @Value("${fiscal.event.datasource}") private String fiscalEventDataSource; diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java index 5c0cdca7..e458d37d 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/FiscalEventConfiguration.java @@ -11,10 +11,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; -import org.springframework.jdbc.core.JdbcTemplate; -import org.springframework.jdbc.datasource.DriverManagerDataSource; -import javax.sql.DataSource; import java.util.TimeZone; @@ -50,19 +47,4 @@ public DruidClient getDruidClient() { } return client; } - - public DataSource getDS() { - DriverManagerDataSource dataSource = new DriverManagerDataSource(); - dataSource.setDriverClassName(configProperties.getPostgresDatasourceDriverClassName()); - dataSource.setUrl(configProperties.getPostgresDatasourceUrl()); - dataSource.setUsername(configProperties.getPostgresDatasourceUsername()); - dataSource.setPassword(configProperties.getPostgresDatasourcePassword()); - return dataSource; - } - - - @Bean - public JdbcTemplate getJdbcTemplate() { - return new JdbcTemplate(getDS()); - } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index b1511fdc..21734ee7 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -29,7 +29,10 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; @Component @Slf4j @@ -61,8 +64,11 @@ public void fetchFiscalEventFromDruid() { List distinctCoaIdResponses = null; try { groupByResponses = druidClient.query(groupByQuery, Object.class); + log.info("Size of record returned from Group by query : {}",groupByResponses.size()); distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); + log.info("Size of record returned from distinct project id query : {}",distinctProjectResponses.size()); distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); + log.info("Size of record returned from distinct coa id query : {}",distinctCoaIdResponses.size()); } catch (QueryException e) { log.error("Exception occurred while quering the data from druid data store : {}", e.getDruidError()); } @@ -84,7 +90,7 @@ public void fetchFiscalEventFromDruid() { //pass the list for upsert if (fiscalEventAggregateList != null && !fiscalEventAggregateList.isEmpty()) { int[] upsertedRecord = aggregateRepository.upsert(fiscalEventAggregateList); - log.debug("Record -> {} upserted successfully", upsertedRecord); + log.info("Record -> {} upserted successfully!", upsertedRecord != null ? upsertedRecord.length : 0); } } From b3a0c713f0595994462441329922ac4f8fa37b28 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Wed, 22 Sep 2021 12:36:55 +0530 Subject: [PATCH 55/67] moved migration script into main folder --- .../src/main/resources/application.properties | 2 +- .../{ => main}/V20210921173000__fiscal_event_aggregate.sql | 0 2 files changed, 1 insertion(+), 1 deletion(-) rename reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/{ => main}/V20210921173000__fiscal_event_aggregate.sql (100%) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index f5528b1a..c503a31a 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -20,7 +20,7 @@ flyway.password=postgres flyway.table=public flyway.baseline-on-migrate=true flyway.outOfOrder=true -flyway.locations=classpath:/db/migration +flyway.locations=classpath:/db/migration/main flyway.enabled=true spring.flyway.baseline-on-migrate = true diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210921173000__fiscal_event_aggregate.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210921173000__fiscal_event_aggregate.sql similarity index 100% rename from reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/V20210921173000__fiscal_event_aggregate.sql rename to reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210921173000__fiscal_event_aggregate.sql From ef03c8f5490e84df7118a6c624f6e33524bccc33 Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Wed, 22 Sep 2021 18:02:05 +0530 Subject: [PATCH 56/67] Removed dockerfile for flyway db migration --- .../src/main/resources/db/Dockerfile | 9 --------- .../src/main/resources/db/migrate.sh | 3 --- 2 files changed, 12 deletions(-) delete mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile delete mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile deleted file mode 100644 index a5699ff7..00000000 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/Dockerfile +++ /dev/null @@ -1,9 +0,0 @@ -FROM egovio/flyway:4.1.2 - -COPY ./migration/main /flyway/sql - -COPY migrate.sh /usr/bin/migrate.sh - -RUN chmod +x /usr/bin/migrate.sh - -CMD ["/usr/bin/migrate.sh"] diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh deleted file mode 100644 index 43960b25..00000000 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migrate.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/sh - -flyway -url=$DB_URL -table=$SCHEMA_TABLE -user=$FLYWAY_USER -password=$FLYWAY_PASSWORD -locations=$FLYWAY_LOCATIONS -baselineOnMigrate=true -outOfOrder=true -ignoreMissingMigrations=true migrate \ No newline at end of file From 630a2e3c7003e74e31f1fb05aa94cef985a8e5ed Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Thu, 23 Sep 2021 11:50:54 +0530 Subject: [PATCH 57/67] Updated Flyway environment variable names --- .../src/main/resources/application.properties | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index c503a31a..065d02ce 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -14,15 +14,8 @@ druid.connect.protocol=HTTPS druid.connect.port=443 ##flyway config ## -flyway.url=jdbc:postgresql://localhost:5432/fiscal_event -flyway.user=postgres -flyway.password=postgres -flyway.table=public -flyway.baseline-on-migrate=true -flyway.outOfOrder=true -flyway.locations=classpath:/db/migration/main -flyway.enabled=true - +spring.flyway.enabled=true +spring.flyway.table=fiscal_event_aggregator_schema spring.flyway.baseline-on-migrate = true fiscal.period=2021-22 From 60662e3f465c722d3c06013f7c182491d80c6462 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Mon, 27 Sep 2021 12:44:39 +0530 Subject: [PATCH 58/67] fiscal event aggregate : Pending collection & payment --- .../fiscal-event-aggregator/pom.xml | 2 +- .../processor/DruidDataQueryProcessor.java | 111 +++++++++++++----- .../FiscalEventAggregateProcessor.java | 14 ++- .../FiscalEventAggregatedDataMapper.java | 5 +- .../util/FiscalEventAggregateConstants.java | 10 +- .../util/FiscalEventAggregateUtil.java | 87 +++++++++++++- ...22163000__fiscal_event_aggregate_index.sql | 98 ++++++++++++++++ 7 files changed, 288 insertions(+), 39 deletions(-) create mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql diff --git a/reference-dashboard/fiscal-event-aggregator/pom.xml b/reference-dashboard/fiscal-event-aggregator/pom.xml index f26b2c60..c36b66b9 100644 --- a/reference-dashboard/fiscal-event-aggregator/pom.xml +++ b/reference-dashboard/fiscal-event-aggregator/pom.xml @@ -10,7 +10,7 @@ org.egov fiscal-event-aggregator - 0.1.0-SNAPSHOT + 1.0.0-SNAPSHOT fiscal-event-aggregator Aggregate the fiscal event post processed data diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index 21734ee7..6ce24e41 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -11,6 +11,7 @@ import in.zapr.druid.druidry.dimension.DefaultDimension; import in.zapr.druid.druidry.dimension.DruidDimension; import in.zapr.druid.druidry.dimension.enums.OutputType; +import in.zapr.druid.druidry.filter.SelectorFilter; import in.zapr.druid.druidry.granularity.Granularity; import in.zapr.druid.druidry.granularity.PredefinedGranularity; import in.zapr.druid.druidry.granularity.SimpleGranularity; @@ -21,7 +22,6 @@ import org.apache.commons.lang3.StringUtils; import org.egov.ifix.aggregate.config.ConfigProperties; import org.egov.ifix.aggregate.model.FiscalEventAggregate; -import org.egov.ifix.aggregate.repository.FiscalEventAggregateRepository; import org.egov.ifix.aggregate.util.FiscalEventAggregateConstants; import org.egov.ifix.aggregate.util.FiscalEventAggregateUtil; import org.joda.time.DateTime; @@ -47,51 +47,110 @@ public class DruidDataQueryProcessor { @Autowired private FiscalEventAggregateUtil aggregateUtil; - @Autowired - private FiscalEventAggregateRepository aggregateRepository; - /** * Fetch the fiscal event data with total sum amount , count from druid date store * based on the group of project id, coa id, event type + * @return */ - public void fetchFiscalEventFromDruid() { + public List fetchFiscalEventFromDruid() { DruidQuery groupByQuery = getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(); DruidQuery distinctProjectQuery = getDruidQueryForProjectDetails(); DruidQuery distinctCoaIdQuery = getDruidQueryForCoaDetails(); + DruidQuery demandEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_DEMAND); + DruidQuery receiptEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_RECEIPT); + DruidQuery billEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_BILL); + DruidQuery paymentEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_PAYMENT); List groupByResponses = null; List distinctProjectResponses = null; List distinctCoaIdResponses = null; + List demandEventTypeResponses = null; + List receiptEventTypeResponses = null; + List billEventTypeResponses = null; + List paymentEventTypeResponses = null; try { groupByResponses = druidClient.query(groupByQuery, Object.class); - log.info("Size of record returned from Group by query : {}",groupByResponses.size()); + log.info("Size of record returned from Group by query : {}", groupByResponses.size()); distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); - log.info("Size of record returned from distinct project id query : {}",distinctProjectResponses.size()); + log.info("Size of record returned from distinct project id query : {}", distinctProjectResponses.size()); distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); - log.info("Size of record returned from distinct coa id query : {}",distinctCoaIdResponses.size()); + log.info("Size of record returned from distinct coa id query : {}", distinctCoaIdResponses.size()); + + demandEventTypeResponses = druidClient.query(demandEventTypeQuery, Object.class); + log.info("Size of record returned from demand event type query : {}", demandEventTypeResponses.size()); + receiptEventTypeResponses = druidClient.query(receiptEventTypeQuery, Object.class); + log.info("Size of record returned from receipt event type query : {}", receiptEventTypeResponses.size()); + + billEventTypeResponses = druidClient.query(billEventTypeQuery, Object.class); + log.info("Size of record returned from bill event type query : {}", billEventTypeResponses.size()); + paymentEventTypeResponses = druidClient.query(paymentEventTypeQuery, Object.class); + log.info("Size of record returned from payment event type query : {}", paymentEventTypeResponses.size()); } catch (QueryException e) { log.error("Exception occurred while quering the data from druid data store : {}", e.getDruidError()); } log.debug("Group by Response : {}", groupByResponses); if (groupByResponses == null || groupByResponses.isEmpty()) { log.info("There are no fiscal event data with group by of project id, event type and coa id"); - return; + return null; } //Create a map of key as project id and event node details as value Map projectNodeMap = aggregateUtil.getProjectDetailsMap(distinctProjectResponses); //Create a map of key as coa id and event node details as value Map coaNodeMap = aggregateUtil.getCOADetailsMap(distinctCoaIdResponses); - //Get the details by project id and coa id map key and create a final List - List fiscalEventAggregateList = aggregateUtil.getFiscalEventAggregateData(groupByResponses - , projectNodeMap, coaNodeMap - , configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD); - - //pass the list for upsert - if (fiscalEventAggregateList != null && !fiscalEventAggregateList.isEmpty()) { - int[] upsertedRecord = aggregateRepository.upsert(fiscalEventAggregateList); - log.info("Record -> {} upserted successfully!", upsertedRecord != null ? upsertedRecord.length : 0); - } + + //Create a map of key as project id and demand event node details as value + Map demandEventTypeNodeMap = aggregateUtil.getEventTypeMap(demandEventTypeResponses); + //Create a map of key as project id and receipt event node details as value + Map receiptEventTypeNodeMap = aggregateUtil.getEventTypeMap(receiptEventTypeResponses); + + //Create a map of key as project id and bill event node details as value + Map billEventTypeNodeMap = aggregateUtil.getEventTypeMap(billEventTypeResponses); + //Create a map of key as project id and payment event node details as value + Map paymentEventTypeNodeMap = aggregateUtil.getEventTypeMap(paymentEventTypeResponses); + + //Get the PENDING_COLLECTION aggregated fiscal event data + List pendingCollectionAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(demandEventTypeNodeMap, receiptEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_COLLECTION); + //Get the PENDING PAYMENT aggregated fiscal event data + List pendingPaymentAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(billEventTypeNodeMap, paymentEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_PAYMENT); + //Get the details by project id and coa id map key and create a List + List fiscalEventAggregates = aggregateUtil.getFiscalEventAggregateData(groupByResponses + , projectNodeMap, coaNodeMap); + + fiscalEventAggregates.addAll(pendingCollectionAggregatedList); + fiscalEventAggregates.addAll(pendingPaymentAggregatedList); + + return fiscalEventAggregates; + } + + private DruidQuery getDruidQueryForProjectIdAndSumAmountBy(String eventType) { + TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); + + Map intervalYearMap = aggregateUtil.getIntervalYearMap(); + + DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + Interval interval = new Interval(startTime, endTime); + + Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); + + DruidDimension druidDimension = new DefaultDimension("project.id", "project.id", OutputType.STRING); + + SelectorFilter filter = new SelectorFilter("eventType", eventType); + + List aggregators = new ArrayList<>(); + aggregators.add(new DoubleSumAggregator("amount", "amount")); + + return (DruidGroupByQuery.builder() + .dataSource(dataSource) + .dimensions(Collections.singletonList(druidDimension)) + .granularity(granularity) + .filter(filter) + .aggregators(aggregators) + .intervals(Collections.singletonList(interval)) + .build()); } @@ -136,6 +195,7 @@ private DruidQuery getDruidQueryForCoaDetails() { .build()); } + private DruidQuery getDruidQueryForProjectDetails() { TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); Map intervalYearMap = aggregateUtil.getIntervalYearMap(); @@ -170,19 +230,6 @@ private DruidQuery getDruidQueryForProjectDetails() { druidDimensions.add(new DefaultDimension("project.code", "project.code", OutputType.STRING)); druidDimensions.add(new DefaultDimension("project.name", "project.name", OutputType.STRING)); -// druidDimensions.add(new DefaultDimension("id", "id", OutputType.STRING)); -// druidDimensions.add(new DefaultDimension("ingestionTime", "ingestionTime", OutputType.LONG)); -// druidDimensions.add(new DefaultDimension("payment", "payment", OutputType.DOUBLE)); -// druidDimensions.add(new DefaultDimension("referenceId", "referenceId", OutputType.STRING)); -// druidDimensions.add(new DefaultDimension("receipt", "receipt", OutputType.DOUBLE)); -// druidDimensions.add(new DefaultDimension("eventId", "eventId", OutputType.STRING)); -// druidDimensions.add(new DefaultDimension("eventType", "eventType", OutputType.STRING)); -// druidDimensions.add(new DefaultDimension("fromBillingPeriod", "fromBillingPeriod", OutputType.LONG)); -// druidDimensions.add(new DefaultDimension("toBillingPeriod", "toBillingPeriod", OutputType.LONG)); -// druidDimensions.add(new DefaultDimension("bill", "bill", OutputType.DOUBLE)); -// druidDimensions.add(new DefaultDimension("demand", "demand", OutputType.DOUBLE)); -// druidDimensions.add(new DefaultDimension("version", "version", OutputType.STRING)); - int hierarchyLevel = FiscalEventAggregateConstants.DEFAULT_HIERARCHY_LEVEL; if (StringUtils.isNotBlank(configProperties.getDepartmentHierarchyLevel())) { hierarchyLevel = Integer.parseInt(configProperties.getDepartmentHierarchyLevel()); diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java index badba851..de2387a4 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/FiscalEventAggregateProcessor.java @@ -1,11 +1,15 @@ package org.egov.ifix.aggregate.processor; import lombok.extern.slf4j.Slf4j; +import org.egov.ifix.aggregate.model.FiscalEventAggregate; +import org.egov.ifix.aggregate.repository.FiscalEventAggregateRepository; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.ApplicationArguments; import org.springframework.boot.ApplicationRunner; import org.springframework.stereotype.Component; +import java.util.List; + @Slf4j @Component public class FiscalEventAggregateProcessor implements ApplicationRunner { @@ -13,8 +17,16 @@ public class FiscalEventAggregateProcessor implements ApplicationRunner { @Autowired private DruidDataQueryProcessor druidDataQueryProcessor; + @Autowired + private FiscalEventAggregateRepository aggregateRepository; + @Override public void run(ApplicationArguments args) throws Exception { - druidDataQueryProcessor.fetchFiscalEventFromDruid(); + List fiscalEventAggregateList = druidDataQueryProcessor.fetchFiscalEventFromDruid(); + //pass the list for upsert + if (fiscalEventAggregateList != null && !fiscalEventAggregateList.isEmpty()) { + int[] upsertedRecord = aggregateRepository.upsert(fiscalEventAggregateList); + log.info("Record -> {} upserted successfully!", upsertedRecord != null ? upsertedRecord.length : 0); + } } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java index c7ace02c..89bd8a83 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java @@ -4,6 +4,7 @@ import org.springframework.jdbc.core.BatchPreparedStatementSetter; import org.springframework.stereotype.Component; +import java.math.BigInteger; import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.List; @@ -28,7 +29,7 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { ps.setString(5, fiscalEventAggregate.getType()); ps.setBigDecimal(6, fiscalEventAggregate.getSumAmount()); ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); - ps.setLong(8, Long.parseLong(fiscalEventAggregate.getCount().toString()));// + ps.setLong(8, Long.parseLong(fiscalEventAggregate.getCount()!=null ? fiscalEventAggregate.getCount().toString() : "0")); ps.setString(9, fiscalEventAggregate.getDepartment_id()); ps.setString(10, fiscalEventAggregate.getDepartment_code()); ps.setString(11, fiscalEventAggregate.getDepartment_name()); @@ -136,7 +137,7 @@ public void setValues(PreparedStatement ps, int i) throws SQLException { //ps.setString(5, fiscalEventAggregate.getEventType()); ps.setBigDecimal(86, fiscalEventAggregate.getSumAmount()); //ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); - ps.setLong(87, Long.parseLong(fiscalEventAggregate.getCount().toString()));// + ps.setLong(87, Long.parseLong(fiscalEventAggregate.getCount()!=null ? fiscalEventAggregate.getCount().toString() : "0"));// ps.setString(88, fiscalEventAggregate.getDepartment_id()); ps.setString(89, fiscalEventAggregate.getDepartment_code()); ps.setString(90, fiscalEventAggregate.getDepartment_name()); diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java index 463c5bb9..234dee2d 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -8,5 +8,13 @@ private FiscalEventAggregateConstants(){} public static final String START_YEAR = "START_YEAR"; public static final String END_YEAR = "END_YEAR"; public static final int DEFAULT_HIERARCHY_LEVEL = 6; - public static final String VER = "0.1.0"; + public static final String VER = "1.0.0"; + + public static final String EVENT_TYPE_DEMAND= "DEMAND"; + public static final String EVENT_TYPE_RECEIPT= "RECEIPT"; + public static final String EVENT_TYPE_PAYMENT = "PAYMENT"; + public static final String EVENT_TYPE_BILL= "BILL"; + + public static final String EVENT_TYPE_PENDING_COLLECTION = "PENDING_COLLECTION"; + public static final String EVENT_TYPE_PENDING_PAYMENT = "PENDING_PAYMENT"; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java index 6df77fe6..be1d86db 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java @@ -85,10 +85,9 @@ public Map getIntervalYearMap() { * @param groupByResponses * @param projectNodeMap * @param coaNodeMap - * @param fiscalPeriod * @return */ - public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap, String fiscalPeriod) { + public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap) { List fiscalEventAggregateList = new ArrayList<>(); JsonNode responseJsonNode = objectMapper.convertValue(groupByResponses, JsonNode.class); Iterator nodeIterator = responseJsonNode.iterator(); @@ -111,6 +110,7 @@ public List getFiscalEventAggregateData(List group eventAggregate.setType(eventType); eventAggregate.setVer(FiscalEventAggregateConstants.VER); + String fiscalPeriod = configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD; eventAggregate.setFiscalPeriod(fiscalPeriod); //set the project details to fiscal event aggregate setProjectDetailsToFiscalEventAggregate(projectNodeMap, eventAggregate, projectId); @@ -309,4 +309,87 @@ private void setProjectDetailsToFiscalEventAggregate(Map proje } } + public Map getEventTypeMap(List eventTypeResponses) { + if (eventTypeResponses == null || eventTypeResponses.isEmpty()) { + return Collections.emptyMap(); + } + JsonNode responseJsonNode = objectMapper.convertValue(eventTypeResponses, JsonNode.class); + Iterator nodeIterator = responseJsonNode.iterator(); + Map projectNodeMap = new HashMap<>(); + while (nodeIterator.hasNext()) { + JsonNode node = nodeIterator.next(); + if (node != null && !node.isEmpty() && node.get("event") != null) { + JsonNode eventNode = node.get("event"); + if (eventNode.get("project.id") != null) { + projectNodeMap.put(eventNode.get("project.id").asText(), eventNode); + } + } + } + return projectNodeMap; + } + + /** + * + * @param firstEventTypeNodeMap - will be demand or bill + * @param secondEventTypeNodeMap - will be receipt or payment + * @param projectNodeMap + * @param pendingEventType + * @return + */ + public List getPendingCollectionFiscalEventAggregatedData(Map firstEventTypeNodeMap, Map secondEventTypeNodeMap, Map projectNodeMap, String pendingEventType) { + List fiscalEventAggregateList = new ArrayList<>(); + + Map pendingAmountMap = new HashMap<>(); + //pending collection Amount + if (firstEventTypeNodeMap != null && !firstEventTypeNodeMap.isEmpty()) { + for (String dPid : firstEventTypeNodeMap.keySet()) { + boolean isAvail = false; + JsonNode demandJsonNode = firstEventTypeNodeMap.get(dPid); + BigDecimal dAmt = demandJsonNode.get("amount") != null ? demandJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + for (String rPid : secondEventTypeNodeMap.keySet()) { + if (dPid.equalsIgnoreCase(rPid)) { + isAvail = true; + JsonNode receiptJsonNode = secondEventTypeNodeMap.get(rPid); + BigDecimal rAmt = receiptJsonNode.get("amount") != null ? receiptJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + pendingAmountMap.put(dPid, (dAmt.subtract(rAmt))); + } + } + if (!isAvail) { + pendingAmountMap.put(dPid, dAmt); + } + } + } + //In case any receipt project id that has no demand type + if (!pendingAmountMap.isEmpty() && !secondEventTypeNodeMap.isEmpty()) { + for (String rPid : secondEventTypeNodeMap.keySet()) { + if (!pendingAmountMap.containsKey(rPid)) { + JsonNode receiptJsonNode = secondEventTypeNodeMap.get(rPid); + BigDecimal rAmt = receiptJsonNode.get("amount") != null ? receiptJsonNode.get("amount").decimalValue() : BigDecimal.ZERO; + pendingAmountMap.put(rPid, BigDecimal.ZERO.subtract(rAmt)); + } + } + } + + //Create a fiscal event aggregated data for pending collections + if(!pendingAmountMap.isEmpty()){ + for(String pid : pendingAmountMap.keySet()){ + FiscalEventAggregate pendingEventAggregate = new FiscalEventAggregate(); + + pendingEventAggregate.setVer(FiscalEventAggregateConstants.VER); + String fiscalPeriod = configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD; + pendingEventAggregate.setFiscalPeriod(fiscalPeriod); + pendingEventAggregate.setProject_id(pid); + pendingEventAggregate.setCount(null); + pendingEventAggregate.setSumAmount(pendingAmountMap.get(pid)); + pendingEventAggregate.setType(pendingEventType); + + //set the project details to fiscal event aggregate + setProjectDetailsToFiscalEventAggregate(projectNodeMap, pendingEventAggregate, pid); + + fiscalEventAggregateList.add(pendingEventAggregate); + } + } + + return fiscalEventAggregateList; + } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql new file mode 100644 index 00000000..c8f97ebb --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/db/migration/main/V20210922163000__fiscal_event_aggregate_index.sql @@ -0,0 +1,98 @@ +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_sumAmount ON fiscal_event_aggregated (sumAmount); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_count ON fiscal_event_aggregated (count); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_fiscalPeriod ON fiscal_event_aggregated (fiscalPeriod); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_type ON fiscal_event_aggregated (type); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_tenantId ON fiscal_event_aggregated (tenantId); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_government_id ON fiscal_event_aggregated (government_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_government_name ON fiscal_event_aggregated (government_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_id ON fiscal_event_aggregated (department_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_code ON fiscal_event_aggregated (department_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_department_name ON fiscal_event_aggregated (department_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_code ON fiscal_event_aggregated (departmentEntity_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_hierarchyLevel); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_id ON fiscal_event_aggregated (departmentEntity_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_name ON fiscal_event_aggregated (departmentEntity_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_id ON fiscal_event_aggregated (departmentEntity_ancestry_0_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_code ON fiscal_event_aggregated (departmentEntity_ancestry_0_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_name ON fiscal_event_aggregated (departmentEntity_ancestry_0_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_0_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_0_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_id ON fiscal_event_aggregated (departmentEntity_ancestry_1_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_code ON fiscal_event_aggregated (departmentEntity_ancestry_1_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_name ON fiscal_event_aggregated (departmentEntity_ancestry_1_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_1_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_1_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_id ON fiscal_event_aggregated (departmentEntity_ancestry_2_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_code ON fiscal_event_aggregated (departmentEntity_ancestry_2_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_name ON fiscal_event_aggregated (departmentEntity_ancestry_2_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_2_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_2_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_id ON fiscal_event_aggregated (departmentEntity_ancestry_3_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_code ON fiscal_event_aggregated (departmentEntity_ancestry_3_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_name ON fiscal_event_aggregated (departmentEntity_ancestry_3_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_3_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_3_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_id ON fiscal_event_aggregated (departmentEntity_ancestry_4_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_code ON fiscal_event_aggregated (departmentEntity_ancestry_4_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_name ON fiscal_event_aggregated (departmentEntity_ancestry_4_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_4_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_4_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_id ON fiscal_event_aggregated (departmentEntity_ancestry_5_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_code ON fiscal_event_aggregated (departmentEntity_ancestry_5_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_name ON fiscal_event_aggregated (departmentEntity_ancestry_5_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_5_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_5_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_id ON fiscal_event_aggregated (departmentEntity_ancestry_6_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_code ON fiscal_event_aggregated (departmentEntity_ancestry_6_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_name ON fiscal_event_aggregated (departmentEntity_ancestry_6_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_6_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_6_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_id ON fiscal_event_aggregated (departmentEntity_ancestry_7_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_code ON fiscal_event_aggregated (departmentEntity_ancestry_7_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_name ON fiscal_event_aggregated (departmentEntity_ancestry_7_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_7_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_7_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_id ON fiscal_event_aggregated (departmentEntity_ancestry_8_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_code ON fiscal_event_aggregated (departmentEntity_ancestry_8_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_name ON fiscal_event_aggregated (departmentEntity_ancestry_8_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_8_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_8_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_id ON fiscal_event_aggregated (departmentEntity_ancestry_9_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_code ON fiscal_event_aggregated (departmentEntity_ancestry_9_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_name ON fiscal_event_aggregated (departmentEntity_ancestry_9_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_9_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_9_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_id ON fiscal_event_aggregated (departmentEntity_ancestry_10_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_code ON fiscal_event_aggregated (departmentEntity_ancestry_10_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_name ON fiscal_event_aggregated (departmentEntity_ancestry_10_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_departmentEntity_ancestry_10_hierarchyLevel ON fiscal_event_aggregated (departmentEntity_ancestry_10_hierarchyLevel); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_id ON fiscal_event_aggregated (expenditure_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_code ON fiscal_event_aggregated (expenditure_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_name ON fiscal_event_aggregated (expenditure_name); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_expenditure_type ON fiscal_event_aggregated (expenditure_type); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_id ON fiscal_event_aggregated (project_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_code ON fiscal_event_aggregated (project_code); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_project_name ON fiscal_event_aggregated (project_name); + +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_id ON fiscal_event_aggregated (coa_id); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_coaCode ON fiscal_event_aggregated (coa_coaCode); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHead ON fiscal_event_aggregated (coa_majorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHeadName ON fiscal_event_aggregated (coa_majorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_majorHeadType ON fiscal_event_aggregated (coa_majorHeadType); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subMajorHead ON fiscal_event_aggregated (coa_subMajorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subMajorHeadName ON fiscal_event_aggregated (coa_subMajorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_minorHead ON fiscal_event_aggregated (coa_minorHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_minorHeadName ON fiscal_event_aggregated (coa_minorHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subHead ON fiscal_event_aggregated (coa_subHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_subHeadName ON fiscal_event_aggregated (coa_subHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_groupHead ON fiscal_event_aggregated (coa_groupHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_groupHeadName ON fiscal_event_aggregated (coa_groupHeadName); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_objectHead ON fiscal_event_aggregated (coa_objectHead); +CREATE INDEX IF NOT EXISTS index_fiscal_event_aggregated_coa_objectHeadName ON fiscal_event_aggregated (coa_objectHeadName); From 7d219682f53f7db6e39e1e260d2682e31552b13a Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Tue, 28 Sep 2021 16:32:28 +0530 Subject: [PATCH 59/67] update issue fix for null coa id --- .../org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java index be1d86db..3d25e63d 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java @@ -386,6 +386,8 @@ public List getPendingCollectionFiscalEventAggregatedData( //set the project details to fiscal event aggregate setProjectDetailsToFiscalEventAggregate(projectNodeMap, pendingEventAggregate, pid); + //Handle the unique update on conflict + pendingEventAggregate.setCoa_id(""); fiscalEventAggregateList.add(pendingEventAggregate); } } From 8e193d260f0b061d86062718630bbc531a1c8334 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Tue, 28 Sep 2021 17:36:16 +0530 Subject: [PATCH 60/67] IFIX 557 : documentation --- .../fiscal-event-aggregator/CHANGELOG.md | 5 ++++ .../fiscal-event-aggregator/LOCALSETUP.md | 13 +++++++++++ .../fiscal-event-aggregator/README.md | 23 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 reference-dashboard/fiscal-event-aggregator/CHANGELOG.md create mode 100644 reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md create mode 100644 reference-dashboard/fiscal-event-aggregator/README.md diff --git a/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md b/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md new file mode 100644 index 00000000..43928dc4 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/CHANGELOG.md @@ -0,0 +1,5 @@ +# Changelog +All notable changes to this module will be documented in this file. + +## 1.0.0 - 2021-09-24 +- Baseline version released diff --git a/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md b/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md new file mode 100644 index 00000000..e3dc6f21 --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/LOCALSETUP.md @@ -0,0 +1,13 @@ +# Local Setup + +To setup the fiscal event aggregate in your local system, clone the [fiscal-event-aggregate](https://github.com/egovernments/iFix-Dev/tree/develop/reference-dashboard). + + +## Infra Dependency + +- [x] Postgres DB +- [x] Druid DB + +## Running Locally + +Run as standalone java program in your local system. diff --git a/reference-dashboard/fiscal-event-aggregator/README.md b/reference-dashboard/fiscal-event-aggregator/README.md new file mode 100644 index 00000000..158a5aff --- /dev/null +++ b/reference-dashboard/fiscal-event-aggregator/README.md @@ -0,0 +1,23 @@ +# fiscal event aggregator + +Fiscal Event Aggregator is a java standalone application, which will be running as cron job to aggregate the fiscal event data from Druid data store to Postgres DB.It will pull all the fiscal event data as + +1. Group by of project id, coa id and event type And sum of amounts. +2. Pending collection(s) w.r.t distinct project id(s). +3. Pending payment(s) w.r.t distinct project id(s). + +Aggregate these all data and push it to postgres DB. + +# Running in Specific environment + +This service has been configured as cron job. Hence to run this service , first check in the specific environment that this service has been configured as cron job or not. To check run the below command + +```bash +kubectl get cronjobs +``` +If you want to run this program manually, use the below command + +```bash +kubectl create job --from=cronjob/fiscal-event-aggregator +``` +You can use custom name in place of "manual-job-name". \ No newline at end of file From 6ef169b9a10749f55efa5194bfe4f5c342df20f8 Mon Sep 17 00:00:00 2001 From: rushang7-eGov Date: Fri, 8 Oct 2021 13:47:00 +0530 Subject: [PATCH 61/67] Renamed EventType enum to Pascal_Case. --- .../util/FiscalEventAggregateConstants.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java index 234dee2d..c2cda30d 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -10,11 +10,11 @@ private FiscalEventAggregateConstants(){} public static final int DEFAULT_HIERARCHY_LEVEL = 6; public static final String VER = "1.0.0"; - public static final String EVENT_TYPE_DEMAND= "DEMAND"; - public static final String EVENT_TYPE_RECEIPT= "RECEIPT"; - public static final String EVENT_TYPE_PAYMENT = "PAYMENT"; - public static final String EVENT_TYPE_BILL= "BILL"; + public static final String EVENT_TYPE_DEMAND= "Demand"; + public static final String EVENT_TYPE_RECEIPT= "Receipt"; + public static final String EVENT_TYPE_PAYMENT = "Payment"; + public static final String EVENT_TYPE_BILL= "Bill"; - public static final String EVENT_TYPE_PENDING_COLLECTION = "PENDING_COLLECTION"; - public static final String EVENT_TYPE_PENDING_PAYMENT = "PENDING_PAYMENT"; + public static final String EVENT_TYPE_PENDING_COLLECTION = "Pending_Collection"; + public static final String EVENT_TYPE_PENDING_PAYMENT = "Pending_Payment"; } From 022b876d69f62b70ddb4373ebce847916fda2ff7 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Wed, 20 Oct 2021 11:27:47 +0530 Subject: [PATCH 62/67] IFIX-589 : Dynamic fiscal period --- .../aggregate/config/ConfigProperties.java | 3 - .../processor/DruidDataQueryProcessor.java | 175 +++++++++--------- .../util/FiscalEventAggregateConstants.java | 5 +- .../util/FiscalEventAggregateUtil.java | 48 ++--- .../src/main/resources/application.properties | 1 - 5 files changed, 115 insertions(+), 117 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java index 7a5c8c80..a0031512 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -26,9 +26,6 @@ public class ConfigProperties { @Value("${druid.connect.port}") private String druidConnectPort; - @Value("${fiscal.period}") - private String fiscalPeriod; - @Value("${department.hierarchy.level}") private String departmentHierarchyLevel; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index 6ce24e41..144ecc2e 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -53,85 +53,90 @@ public class DruidDataQueryProcessor { * @return */ public List fetchFiscalEventFromDruid() { - DruidQuery groupByQuery = getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(); - DruidQuery distinctProjectQuery = getDruidQueryForProjectDetails(); - DruidQuery distinctCoaIdQuery = getDruidQueryForCoaDetails(); - DruidQuery demandEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_DEMAND); - DruidQuery receiptEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_RECEIPT); - DruidQuery billEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_BILL); - DruidQuery paymentEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_PAYMENT); - - List groupByResponses = null; - List distinctProjectResponses = null; - List distinctCoaIdResponses = null; - List demandEventTypeResponses = null; - List receiptEventTypeResponses = null; - List billEventTypeResponses = null; - List paymentEventTypeResponses = null; - try { - groupByResponses = druidClient.query(groupByQuery, Object.class); - log.info("Size of record returned from Group by query : {}", groupByResponses.size()); - distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); - log.info("Size of record returned from distinct project id query : {}", distinctProjectResponses.size()); - distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); - log.info("Size of record returned from distinct coa id query : {}", distinctCoaIdResponses.size()); - - demandEventTypeResponses = druidClient.query(demandEventTypeQuery, Object.class); - log.info("Size of record returned from demand event type query : {}", demandEventTypeResponses.size()); - receiptEventTypeResponses = druidClient.query(receiptEventTypeQuery, Object.class); - log.info("Size of record returned from receipt event type query : {}", receiptEventTypeResponses.size()); - - billEventTypeResponses = druidClient.query(billEventTypeQuery, Object.class); - log.info("Size of record returned from bill event type query : {}", billEventTypeResponses.size()); - paymentEventTypeResponses = druidClient.query(paymentEventTypeQuery, Object.class); - log.info("Size of record returned from payment event type query : {}", paymentEventTypeResponses.size()); - } catch (QueryException e) { - log.error("Exception occurred while quering the data from druid data store : {}", e.getDruidError()); + Map fiscalYearMap = aggregateUtil.getFiscalYear(); + List finalFiscalEventAggregates = new ArrayList<>(); + + for (String fyKey : fiscalYearMap.keySet()) { + int fiscalYear = fiscalYearMap.get(fyKey); + + DruidQuery groupByQuery = getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(fiscalYear); + DruidQuery distinctProjectQuery = getDruidQueryForProjectDetails(fiscalYear); + DruidQuery distinctCoaIdQuery = getDruidQueryForCoaDetails(fiscalYear); + DruidQuery demandEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_DEMAND,fiscalYear); + DruidQuery receiptEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_RECEIPT,fiscalYear); + DruidQuery billEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_BILL,fiscalYear); + DruidQuery paymentEventTypeQuery = getDruidQueryForProjectIdAndSumAmountBy(FiscalEventAggregateConstants.EVENT_TYPE_PAYMENT,fiscalYear); + + List groupByResponses = null; + List distinctProjectResponses = null; + List distinctCoaIdResponses = null; + List demandEventTypeResponses = null; + List receiptEventTypeResponses = null; + List billEventTypeResponses = null; + List paymentEventTypeResponses = null; + try { + groupByResponses = druidClient.query(groupByQuery, Object.class); + log.info("Size of record returned from Group by query : {} for fiscal year : {}", groupByResponses.size(), fiscalYear); + distinctProjectResponses = druidClient.query(distinctProjectQuery, Object.class); + log.info("Size of record returned from distinct project id query : {} for fiscal year : {}", distinctProjectResponses.size(), fiscalYear); + distinctCoaIdResponses = druidClient.query(distinctCoaIdQuery, Object.class); + log.info("Size of record returned from distinct coa id query : {} for fiscal year : {}", distinctCoaIdResponses.size(), fiscalYear); + + demandEventTypeResponses = druidClient.query(demandEventTypeQuery, Object.class); + log.info("Size of record returned from demand event type query : {} for fiscal year : {}", demandEventTypeResponses.size(), fiscalYear); + receiptEventTypeResponses = druidClient.query(receiptEventTypeQuery, Object.class); + log.info("Size of record returned from receipt event type query : {} for fiscal year : {}", receiptEventTypeResponses.size(), fiscalYear); + + billEventTypeResponses = druidClient.query(billEventTypeQuery, Object.class); + log.info("Size of record returned from bill event type query : {} for fiscal year : {}", billEventTypeResponses.size(), fiscalYear); + paymentEventTypeResponses = druidClient.query(paymentEventTypeQuery, Object.class); + log.info("Size of record returned from payment event type query : {} for fiscal year : {}", paymentEventTypeResponses.size(), fiscalYear); + } catch (QueryException e) { + log.error("Exception occurred while querying the data from druid data store : {}", e.getDruidError()); + } + log.debug("Group by Response : {}", groupByResponses); + if (groupByResponses == null || groupByResponses.isEmpty()) { + log.info("There are no fiscal event data with group by of project id, event type and coa id for fiscal year : {}",fiscalYear); + continue; + } + + //Create a map of key as project id and event node details as value + Map projectNodeMap = aggregateUtil.getProjectDetailsMap(distinctProjectResponses); + //Create a map of key as coa id and event node details as value + Map coaNodeMap = aggregateUtil.getCOADetailsMap(distinctCoaIdResponses); + + //Create a map of key as project id and demand event node details as value + Map demandEventTypeNodeMap = aggregateUtil.getEventTypeMap(demandEventTypeResponses); + //Create a map of key as project id and receipt event node details as value + Map receiptEventTypeNodeMap = aggregateUtil.getEventTypeMap(receiptEventTypeResponses); + + //Create a map of key as project id and bill event node details as value + Map billEventTypeNodeMap = aggregateUtil.getEventTypeMap(billEventTypeResponses); + //Create a map of key as project id and payment event node details as value + Map paymentEventTypeNodeMap = aggregateUtil.getEventTypeMap(paymentEventTypeResponses); + + //Get the PENDING_COLLECTION aggregated fiscal event data + List pendingCollectionAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(demandEventTypeNodeMap, receiptEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_COLLECTION,fiscalYear); + //Get the PENDING PAYMENT aggregated fiscal event data + List pendingPaymentAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(billEventTypeNodeMap, paymentEventTypeNodeMap, projectNodeMap, + FiscalEventAggregateConstants.EVENT_TYPE_PENDING_PAYMENT, fiscalYear); + //Get the details by project id and coa id map key and create a List + List fiscalEventAggregates = aggregateUtil.getFiscalEventAggregateData(groupByResponses + , projectNodeMap, coaNodeMap,fiscalYear); + + finalFiscalEventAggregates.addAll(pendingCollectionAggregatedList); + finalFiscalEventAggregates.addAll(pendingPaymentAggregatedList); + finalFiscalEventAggregates.addAll(fiscalEventAggregates); } - log.debug("Group by Response : {}", groupByResponses); - if (groupByResponses == null || groupByResponses.isEmpty()) { - log.info("There are no fiscal event data with group by of project id, event type and coa id"); - return null; - } - - //Create a map of key as project id and event node details as value - Map projectNodeMap = aggregateUtil.getProjectDetailsMap(distinctProjectResponses); - //Create a map of key as coa id and event node details as value - Map coaNodeMap = aggregateUtil.getCOADetailsMap(distinctCoaIdResponses); - - //Create a map of key as project id and demand event node details as value - Map demandEventTypeNodeMap = aggregateUtil.getEventTypeMap(demandEventTypeResponses); - //Create a map of key as project id and receipt event node details as value - Map receiptEventTypeNodeMap = aggregateUtil.getEventTypeMap(receiptEventTypeResponses); - - //Create a map of key as project id and bill event node details as value - Map billEventTypeNodeMap = aggregateUtil.getEventTypeMap(billEventTypeResponses); - //Create a map of key as project id and payment event node details as value - Map paymentEventTypeNodeMap = aggregateUtil.getEventTypeMap(paymentEventTypeResponses); - - //Get the PENDING_COLLECTION aggregated fiscal event data - List pendingCollectionAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(demandEventTypeNodeMap, receiptEventTypeNodeMap, projectNodeMap, - FiscalEventAggregateConstants.EVENT_TYPE_PENDING_COLLECTION); - //Get the PENDING PAYMENT aggregated fiscal event data - List pendingPaymentAggregatedList = aggregateUtil.getPendingCollectionFiscalEventAggregatedData(billEventTypeNodeMap, paymentEventTypeNodeMap, projectNodeMap, - FiscalEventAggregateConstants.EVENT_TYPE_PENDING_PAYMENT); - //Get the details by project id and coa id map key and create a List - List fiscalEventAggregates = aggregateUtil.getFiscalEventAggregateData(groupByResponses - , projectNodeMap, coaNodeMap); - - fiscalEventAggregates.addAll(pendingCollectionAggregatedList); - fiscalEventAggregates.addAll(pendingPaymentAggregatedList); - - return fiscalEventAggregates; + return finalFiscalEventAggregates; } - private DruidQuery getDruidQueryForProjectIdAndSumAmountBy(String eventType) { + private DruidQuery getDruidQueryForProjectIdAndSumAmountBy(String eventType, int fiscalYear) { TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); - Map intervalYearMap = aggregateUtil.getIntervalYearMap(); - - DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); Interval interval = new Interval(startTime, endTime); Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); @@ -154,13 +159,11 @@ private DruidQuery getDruidQueryForProjectIdAndSumAmountBy(String eventType) { } - private DruidQuery getDruidQueryForCoaDetails() { + private DruidQuery getDruidQueryForCoaDetails(int fiscalYear) { TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); - Map intervalYearMap = aggregateUtil.getIntervalYearMap(); - - DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); Interval interval = new Interval(startTime, endTime); Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); @@ -196,12 +199,11 @@ private DruidQuery getDruidQueryForCoaDetails() { } - private DruidQuery getDruidQueryForProjectDetails() { + private DruidQuery getDruidQueryForProjectDetails(int fiscalYear) { TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); - Map intervalYearMap = aggregateUtil.getIntervalYearMap(); - DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); Interval interval = new Interval(startTime, endTime); Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); @@ -256,12 +258,11 @@ private DruidQuery getDruidQueryForProjectDetails() { .build()); } - private DruidGroupByQuery getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType() { + private DruidGroupByQuery getDruidQueryForGroupbyProjectIdAndCoaIdAndEventType(int fiscalYear) { TableDataSource dataSource = new TableDataSource(configProperties.getFiscalEventDataSource()); - Map intervalYearMap = aggregateUtil.getIntervalYearMap(); - DateTime startTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.START_YEAR), 04, 1, 0, 0, 0, DateTimeZone.UTC); - DateTime endTime = new DateTime(intervalYearMap.get(FiscalEventAggregateConstants.END_YEAR), 03, 31, 0, 0, 0, DateTimeZone.UTC); + DateTime startTime = new DateTime(fiscalYear, 04, 1, 0, 0, 0, DateTimeZone.UTC); + DateTime endTime = new DateTime(fiscalYear + 1, 03, 31, 0, 0, 0, DateTimeZone.UTC); Interval interval = new Interval(startTime, endTime); Granularity granularity = new SimpleGranularity(PredefinedGranularity.ALL); diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java index c2cda30d..26572c6a 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -4,9 +4,8 @@ public class FiscalEventAggregateConstants { private FiscalEventAggregateConstants(){} - public static final String DEFAULT_FISCAL_PERIOD = "2021-22"; - public static final String START_YEAR = "START_YEAR"; - public static final String END_YEAR = "END_YEAR"; + public static final String CURRENT_FISCAL_YEAR = "CURRENT_FISCAL_YEAR"; + public static final String PREVIOUS_FISCAL_YEAR = "PREVIOUS_FISCAL_YEAR"; public static final int DEFAULT_HIERARCHY_LEVEL = 6; public static final String VER = "1.0.0"; diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java index 3d25e63d..f45928e8 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateUtil.java @@ -11,6 +11,7 @@ import java.math.BigDecimal; import java.math.BigInteger; +import java.time.Year; import java.util.*; @Slf4j @@ -63,31 +64,14 @@ public Map getCOADetailsMap(List distinctCoaIdResponse return coaNodeMap; } - public Map getIntervalYearMap() { - Map intervalYearMap = new HashMap<>(); - - String[] defaultFiscalPeriodArr = (FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD).split("-"); - String prefixYear = defaultFiscalPeriodArr[0].substring(0, 2); - int startYear = Integer.parseInt(defaultFiscalPeriodArr[0]); - int endYear = Integer.parseInt(prefixYear.concat(defaultFiscalPeriodArr[1])); - if (StringUtils.isNotBlank(configProperties.getFiscalPeriod())) { - String[] strArr = configProperties.getFiscalPeriod().split("-"); - prefixYear = strArr[0].substring(0, 2); - startYear = Integer.parseInt(strArr[0]); - endYear = Integer.parseInt(strArr[1] != null && strArr[1].length() == 4 ? strArr[1] : prefixYear.concat(strArr[1])); - } - intervalYearMap.put(FiscalEventAggregateConstants.START_YEAR, startYear); - intervalYearMap.put(FiscalEventAggregateConstants.END_YEAR, endYear); - return intervalYearMap; - } - /** * @param groupByResponses * @param projectNodeMap * @param coaNodeMap + * @param fiscalYear * @return */ - public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap) { + public List getFiscalEventAggregateData(List groupByResponses, Map projectNodeMap, Map coaNodeMap, int fiscalYear) { List fiscalEventAggregateList = new ArrayList<>(); JsonNode responseJsonNode = objectMapper.convertValue(groupByResponses, JsonNode.class); Iterator nodeIterator = responseJsonNode.iterator(); @@ -110,7 +94,7 @@ public List getFiscalEventAggregateData(List group eventAggregate.setType(eventType); eventAggregate.setVer(FiscalEventAggregateConstants.VER); - String fiscalPeriod = configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD; + String fiscalPeriod = createFiscalPeriodFrom(fiscalYear); eventAggregate.setFiscalPeriod(fiscalPeriod); //set the project details to fiscal event aggregate setProjectDetailsToFiscalEventAggregate(projectNodeMap, eventAggregate, projectId); @@ -118,7 +102,6 @@ public List getFiscalEventAggregateData(List group //set the coa details to fiscal event aggregate setCoaDetailsToFiscalEventAggregate(coaNodeMap, eventAggregate, coaId); - //TODO : push to kafka fiscalEventAggregateList.add(eventAggregate); } } @@ -334,9 +317,10 @@ public Map getEventTypeMap(List eventTypeResponses) { * @param secondEventTypeNodeMap - will be receipt or payment * @param projectNodeMap * @param pendingEventType + * @param fiscalYear * @return */ - public List getPendingCollectionFiscalEventAggregatedData(Map firstEventTypeNodeMap, Map secondEventTypeNodeMap, Map projectNodeMap, String pendingEventType) { + public List getPendingCollectionFiscalEventAggregatedData(Map firstEventTypeNodeMap, Map secondEventTypeNodeMap, Map projectNodeMap, String pendingEventType, int fiscalYear) { List fiscalEventAggregateList = new ArrayList<>(); Map pendingAmountMap = new HashMap<>(); @@ -376,7 +360,7 @@ public List getPendingCollectionFiscalEventAggregatedData( FiscalEventAggregate pendingEventAggregate = new FiscalEventAggregate(); pendingEventAggregate.setVer(FiscalEventAggregateConstants.VER); - String fiscalPeriod = configProperties.getFiscalPeriod() != null ? configProperties.getFiscalPeriod() : FiscalEventAggregateConstants.DEFAULT_FISCAL_PERIOD; + String fiscalPeriod = createFiscalPeriodFrom(fiscalYear); pendingEventAggregate.setFiscalPeriod(fiscalPeriod); pendingEventAggregate.setProject_id(pid); pendingEventAggregate.setCount(null); @@ -394,4 +378,22 @@ public List getPendingCollectionFiscalEventAggregatedData( return fiscalEventAggregateList; } + + private String createFiscalPeriodFrom(int fiscalYear) { + String fiscalPeriodBuilder = String.valueOf(fiscalYear); + String endFiscalPeriodBuilder = String.valueOf(fiscalYear + 1); + return (fiscalPeriodBuilder.concat("-").concat(endFiscalPeriodBuilder.substring(2))); + } + + /** + * Calculate the fiscal year(s) based on system time. + * @return + */ + public Map getFiscalYear() { + Map fiscalYearMap = new HashMap<>(); + int currentYear = Year.now().getValue(); + fiscalYearMap.put(FiscalEventAggregateConstants.CURRENT_FISCAL_YEAR, currentYear); + fiscalYearMap.put(FiscalEventAggregateConstants.PREVIOUS_FISCAL_YEAR, (currentYear-1)); + return fiscalYearMap; + } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index 065d02ce..f4291862 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -18,5 +18,4 @@ spring.flyway.enabled=true spring.flyway.table=fiscal_event_aggregator_schema spring.flyway.baseline-on-migrate = true -fiscal.period=2021-22 department.hierarchy.level=6 \ No newline at end of file From 762216398f2fc8d4f598ca17f762449110a4e76c Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Thu, 21 Oct 2021 16:42:26 +0530 Subject: [PATCH 63/67] IFIX-589 : Dynamic hierarchy level --- .../org/egov/ifix/aggregate/config/ConfigProperties.java | 2 -- .../ifix/aggregate/processor/DruidDataQueryProcessor.java | 6 +++--- .../ifix/aggregate/util/FiscalEventAggregateConstants.java | 2 +- .../src/main/resources/application.properties | 4 +--- 4 files changed, 5 insertions(+), 9 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java index a0031512..580cfd96 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/config/ConfigProperties.java @@ -26,6 +26,4 @@ public class ConfigProperties { @Value("${druid.connect.port}") private String druidConnectPort; - @Value("${department.hierarchy.level}") - private String departmentHierarchyLevel; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index 144ecc2e..5ca101a7 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -233,9 +233,9 @@ private DruidQuery getDruidQueryForProjectDetails(int fiscalYear) { druidDimensions.add(new DefaultDimension("project.name", "project.name", OutputType.STRING)); int hierarchyLevel = FiscalEventAggregateConstants.DEFAULT_HIERARCHY_LEVEL; - if (StringUtils.isNotBlank(configProperties.getDepartmentHierarchyLevel())) { - hierarchyLevel = Integer.parseInt(configProperties.getDepartmentHierarchyLevel()); - } +// if (StringUtils.isNotBlank(configProperties.getDepartmentHierarchyLevel())) { +// hierarchyLevel = Integer.parseInt(configProperties.getDepartmentHierarchyLevel()); +// } for (int i = 0; i <= hierarchyLevel; i++) { druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].code", "departmentEntity.ancestry[" + i + "].code", OutputType.STRING)); diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java index 26572c6a..c05c6934 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/util/FiscalEventAggregateConstants.java @@ -6,7 +6,7 @@ private FiscalEventAggregateConstants(){} public static final String CURRENT_FISCAL_YEAR = "CURRENT_FISCAL_YEAR"; public static final String PREVIOUS_FISCAL_YEAR = "PREVIOUS_FISCAL_YEAR"; - public static final int DEFAULT_HIERARCHY_LEVEL = 6; + public static final int DEFAULT_HIERARCHY_LEVEL = 10; public static final String VER = "1.0.0"; public static final String EVENT_TYPE_DEMAND= "Demand"; diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index f4291862..d1275979 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -7,7 +7,7 @@ spring.datasource.username=postgres spring.datasource.password=root ## Druid Config ## -druid.host=druid.ifix.org.in +druid.host=druid-qa.ifix.org.in druid.endPoint=druid/v2/ fiscal.event.datasource=fiscal-event druid.connect.protocol=HTTPS @@ -17,5 +17,3 @@ druid.connect.port=443 spring.flyway.enabled=true spring.flyway.table=fiscal_event_aggregator_schema spring.flyway.baseline-on-migrate = true - -department.hierarchy.level=6 \ No newline at end of file From c42b28c7fbc23d72abc6fbc46739d339425b32a8 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Thu, 21 Oct 2021 16:45:29 +0530 Subject: [PATCH 64/67] IFIX-590 : Dynamic hierarchy level --- .../egov/ifix/aggregate/processor/DruidDataQueryProcessor.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java index 5ca101a7..9b2db516 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/processor/DruidDataQueryProcessor.java @@ -233,9 +233,6 @@ private DruidQuery getDruidQueryForProjectDetails(int fiscalYear) { druidDimensions.add(new DefaultDimension("project.name", "project.name", OutputType.STRING)); int hierarchyLevel = FiscalEventAggregateConstants.DEFAULT_HIERARCHY_LEVEL; -// if (StringUtils.isNotBlank(configProperties.getDepartmentHierarchyLevel())) { -// hierarchyLevel = Integer.parseInt(configProperties.getDepartmentHierarchyLevel()); -// } for (int i = 0; i <= hierarchyLevel; i++) { druidDimensions.add(new DefaultDimension("departmentEntity.ancestry[" + i + "].code", "departmentEntity.ancestry[" + i + "].code", OutputType.STRING)); From 8c021cd9341e133db451d3ae3c3789392d170450 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Fri, 22 Oct 2021 15:34:42 +0530 Subject: [PATCH 65/67] named parameters (for query maintenance) --- .../FiscalEventAggregateRepository.java | 14 +- .../mapper/FiscalEventAggregateQuery.java | 113 ++++---- .../FiscalEventAggregatedDataMapper.java | 242 ------------------ 3 files changed, 75 insertions(+), 294 deletions(-) delete mode 100644 reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java index 0382069f..f816119e 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/FiscalEventAggregateRepository.java @@ -3,9 +3,10 @@ import lombok.extern.slf4j.Slf4j; import org.egov.ifix.aggregate.model.FiscalEventAggregate; import org.egov.ifix.aggregate.repository.mapper.FiscalEventAggregateQuery; -import org.egov.ifix.aggregate.repository.mapper.FiscalEventAggregatedDataMapper; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.jdbc.core.JdbcTemplate; +import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate; +import org.springframework.jdbc.core.namedparam.SqlParameterSource; +import org.springframework.jdbc.core.namedparam.SqlParameterSourceUtils; import org.springframework.stereotype.Repository; import java.util.List; @@ -15,11 +16,12 @@ public class FiscalEventAggregateRepository { @Autowired - private JdbcTemplate jdbcTemplate; + private NamedParameterJdbcTemplate namedParameterJdbcTemplate; - public int[] upsert(List fiscalEventAggregates){ - return (jdbcTemplate.batchUpdate(FiscalEventAggregateQuery.UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE - , new FiscalEventAggregatedDataMapper(fiscalEventAggregates))); + public int[] upsert(List fiscalEventAggregates) { + SqlParameterSource[] batch = SqlParameterSourceUtils.createBatch(fiscalEventAggregates.toArray()); + return (namedParameterJdbcTemplate.batchUpdate(FiscalEventAggregateQuery.UPSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE, + batch)); } } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java index cba86e54..910cfcdc 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java @@ -28,54 +28,75 @@ public class FiscalEventAggregateQuery { "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel,departmentEntity_id,departmentEntity_code," + "departmentEntity_name,departmentEntity_hierarchyLevel) " + "VALUES" + - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + - "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?, ?,?,?,?) " + + "(:ver,:tenantId,:government_id,:government_name,:type,:sumAmount,:fiscalPeriod,:count," + + ":department_id,:department_code,:department_name,:expenditure_id,:expenditure_code,:expenditure_name," + + ":expenditure_type,:project_id,:project_code,:project_name," + + ":coa_id,:coa_coaCode,:coa_majorHead,:coa_majorHeadName,:coa_majorHeadType,:coa_subMajorHead,:coa_subMajorHeadName," + + ":coa_minorHead,:coa_minorHeadName,:coa_subHead,:coa_subHeadName,:coa_groupHead,:coa_groupHeadName,:coa_objectHead," + + ":coa_objectHeadName,:departmentEntity_ancestry_0_id,:departmentEntity_ancestry_0_code,:departmentEntity_ancestry_0_name," + + ":departmentEntity_ancestry_0_hierarchyLevel,:departmentEntity_ancestry_1_id,:departmentEntity_ancestry_1_code," + + ":departmentEntity_ancestry_1_name,:departmentEntity_ancestry_1_hierarchyLevel,:departmentEntity_ancestry_2_id," + + ":departmentEntity_ancestry_2_code,:departmentEntity_ancestry_2_name,:departmentEntity_ancestry_2_hierarchyLevel," + + ":departmentEntity_ancestry_3_id,:departmentEntity_ancestry_3_code,:departmentEntity_ancestry_3_name," + + ":departmentEntity_ancestry_3_hierarchyLevel,:departmentEntity_ancestry_4_id,:departmentEntity_ancestry_4_code," + + ":departmentEntity_ancestry_4_name,:departmentEntity_ancestry_4_hierarchyLevel,:departmentEntity_ancestry_5_id," + + ":departmentEntity_ancestry_5_code,:departmentEntity_ancestry_5_name,:departmentEntity_ancestry_5_hierarchyLevel," + + ":departmentEntity_ancestry_6_id,:departmentEntity_ancestry_6_code,:departmentEntity_ancestry_6_name," + + ":departmentEntity_ancestry_6_hierarchyLevel,:departmentEntity_ancestry_7_id,:departmentEntity_ancestry_7_code," + + ":departmentEntity_ancestry_7_name,:departmentEntity_ancestry_7_hierarchyLevel,:departmentEntity_ancestry_8_id," + + ":departmentEntity_ancestry_8_code,:departmentEntity_ancestry_8_name,:departmentEntity_ancestry_8_hierarchyLevel," + + ":departmentEntity_ancestry_9_id,:departmentEntity_ancestry_9_code,:departmentEntity_ancestry_9_name," + + ":departmentEntity_ancestry_9_hierarchyLevel,:departmentEntity_ancestry_10_id,:departmentEntity_ancestry_10_code," + + ":departmentEntity_ancestry_10_name,:departmentEntity_ancestry_10_hierarchyLevel," + + ":departmentEntity_id,:departmentEntity_code,:departmentEntity_name,:departmentEntity_hierarchyLevel) " + "ON CONFLICT(project_id,coa_id,type,fiscalPeriod) " + "DO UPDATE " + "SET " + - "ver=?,tenantId=?,government_id=?,government_name=?,sumAmount=?,count=?,department_id=?," + - "department_code=?,department_name=?,departmentEntity_ancestry_0_id=?," + - "expenditure_id=?,expenditure_code=?,expenditure_name=?,expenditure_type=?,project_code=?,project_name=?," + - "coa_coaCode=?,coa_majorHead=?,coa_majorHeadName=?,coa_majorHeadType=?,coa_subMajorHead=?,coa_subMajorHeadName=?,coa_minorHead=?," + - "coa_minorHeadName=?,coa_subHead=?,coa_subHeadName=?,coa_groupHead=?,coa_groupHeadName=?,coa_objectHead=?,coa_objectHeadName=?, " + - "departmentEntity_ancestry_0_code=?," + - "departmentEntity_ancestry_0_name=?,departmentEntity_ancestry_0_hierarchyLevel=?,departmentEntity_ancestry_1_id=?," + - "departmentEntity_ancestry_1_code=?,departmentEntity_ancestry_1_name=?,departmentEntity_ancestry_1_hierarchyLevel=?," + - "departmentEntity_ancestry_2_id=?,departmentEntity_ancestry_2_code=?,departmentEntity_ancestry_2_name=?," + - "departmentEntity_ancestry_2_hierarchyLevel=?,departmentEntity_ancestry_3_id=?,departmentEntity_ancestry_3_code=?," + - "departmentEntity_ancestry_3_name=?,departmentEntity_ancestry_3_hierarchyLevel=?,departmentEntity_ancestry_4_id=?," + - "departmentEntity_ancestry_4_code=?,departmentEntity_ancestry_4_name=?,departmentEntity_ancestry_4_hierarchyLevel=?," + - "departmentEntity_ancestry_5_id=?,departmentEntity_ancestry_5_code=?,departmentEntity_ancestry_5_name=?," + - "departmentEntity_ancestry_5_hierarchyLevel=?,departmentEntity_ancestry_6_id=?,departmentEntity_ancestry_6_code=?," + - "departmentEntity_ancestry_6_name=?,departmentEntity_ancestry_6_hierarchyLevel=?,departmentEntity_ancestry_7_id=?," + - "departmentEntity_ancestry_7_code=?,departmentEntity_ancestry_7_name=?,departmentEntity_ancestry_7_hierarchyLevel=?," + - "departmentEntity_ancestry_8_id=?,departmentEntity_ancestry_8_code=?,departmentEntity_ancestry_8_name=?," + - "departmentEntity_ancestry_8_hierarchyLevel=?,departmentEntity_ancestry_9_id=?,departmentEntity_ancestry_9_code=?," + - "departmentEntity_ancestry_9_name=?,departmentEntity_ancestry_9_hierarchyLevel=?,departmentEntity_ancestry_10_id=?," + - "departmentEntity_ancestry_10_code=?,departmentEntity_ancestry_10_name=?,departmentEntity_ancestry_10_hierarchyLevel=?," + - "departmentEntity_id=?,departmentEntity_code=?,departmentEntity_name=?,departmentEntity_hierarchyLevel=?;"; + "ver=:ver,tenantId=:tenantId,government_id=:government_id,government_name=:government_name,sumAmount=:sumAmount,count=:count," + + "department_id=:department_id,department_code=:department_code,department_name=:department_name,departmentEntity_ancestry_0_id=:departmentEntity_ancestry_0_id," + + "expenditure_id=:expenditure_id,expenditure_code=:expenditure_code,expenditure_name=:expenditure_name,expenditure_type=:expenditure_type," + + "project_code=:project_code,project_name=:project_name," + + "coa_coaCode=:coa_coaCode,coa_majorHead=:coa_majorHead,coa_majorHeadName=:coa_majorHeadName,coa_majorHeadType=:coa_majorHeadType,coa_subMajorHead=:coa_subMajorHead," + + "coa_subMajorHeadName=:coa_subMajorHeadName,coa_minorHead=:coa_minorHead,coa_minorHeadName=:coa_minorHeadName,coa_subHead=:coa_subHead," + + "coa_subHeadName=:coa_subHeadName,coa_groupHead=:coa_groupHead,coa_groupHeadName=:coa_groupHeadName,coa_objectHead=:coa_objectHead,coa_objectHeadName=:coa_objectHeadName, " + + "departmentEntity_ancestry_0_code=:departmentEntity_ancestry_0_code," + + "departmentEntity_ancestry_0_name=:departmentEntity_ancestry_0_name,departmentEntity_ancestry_0_hierarchyLevel=:departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id=:departmentEntity_ancestry_1_id," + + "departmentEntity_ancestry_1_code=:departmentEntity_ancestry_1_code,departmentEntity_ancestry_1_name=:departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel=:departmentEntity_ancestry_1_hierarchyLevel," + + "departmentEntity_ancestry_2_id=:departmentEntity_ancestry_2_id,departmentEntity_ancestry_2_code=:departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name=:departmentEntity_ancestry_2_name," + + "departmentEntity_ancestry_2_hierarchyLevel=:departmentEntity_ancestry_2_hierarchyLevel,departmentEntity_ancestry_3_id=:departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code=:departmentEntity_ancestry_3_code," + + "departmentEntity_ancestry_3_name=:departmentEntity_ancestry_3_name,departmentEntity_ancestry_3_hierarchyLevel=:departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id=:departmentEntity_ancestry_4_id," + + "departmentEntity_ancestry_4_code=:departmentEntity_ancestry_4_code,departmentEntity_ancestry_4_name=:departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel=:departmentEntity_ancestry_4_hierarchyLevel," + + "departmentEntity_ancestry_5_id=:departmentEntity_ancestry_5_id,departmentEntity_ancestry_5_code=:departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name=:departmentEntity_ancestry_5_name," + + "departmentEntity_ancestry_5_hierarchyLevel=:departmentEntity_ancestry_5_hierarchyLevel,departmentEntity_ancestry_6_id=:departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code=:departmentEntity_ancestry_6_code," + + "departmentEntity_ancestry_6_name=:departmentEntity_ancestry_6_name,departmentEntity_ancestry_6_hierarchyLevel=:departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id=:departmentEntity_ancestry_7_id," + + "departmentEntity_ancestry_7_code=:departmentEntity_ancestry_7_code,departmentEntity_ancestry_7_name=:departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel=:departmentEntity_ancestry_7_hierarchyLevel," + + "departmentEntity_ancestry_8_id=:departmentEntity_ancestry_8_id,departmentEntity_ancestry_8_code=:departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name=:departmentEntity_ancestry_8_name," + + "departmentEntity_ancestry_8_hierarchyLevel=:departmentEntity_ancestry_8_hierarchyLevel,departmentEntity_ancestry_9_id=:departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code=:departmentEntity_ancestry_9_code," + + "departmentEntity_ancestry_9_name=:departmentEntity_ancestry_9_name,departmentEntity_ancestry_9_hierarchyLevel=:departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id=:departmentEntity_ancestry_10_id," + + "departmentEntity_ancestry_10_code=:departmentEntity_ancestry_10_code,departmentEntity_ancestry_10_name=:departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel=:departmentEntity_ancestry_10_hierarchyLevel," + + "departmentEntity_id=:departmentEntity_id,departmentEntity_code=:departmentEntity_code,departmentEntity_name=:departmentEntity_name,departmentEntity_hierarchyLevel=:departmentEntity_hierarchyLevel;"; - public static final String INSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + - "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + - "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + - "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + - "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + - "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ - "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ - "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + - "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + - "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + - "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + - "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + - "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + - "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + - "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + - "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + - "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + - "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + - "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + - "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel) " + - "VALUES" + - "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + - "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ;" ; +// public static final String INSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + +// "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + +// "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + +// "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + +// "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + +// "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ +// "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ +// "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + +// "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + +// "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + +// "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + +// "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + +// "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + +// "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + +// "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + +// "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + +// "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + +// "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + +// "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + +// "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel) " + +// "VALUES" + +// "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + +// "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ;" ; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java deleted file mode 100644 index 89bd8a83..00000000 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregatedDataMapper.java +++ /dev/null @@ -1,242 +0,0 @@ -package org.egov.ifix.aggregate.repository.mapper; - -import org.egov.ifix.aggregate.model.FiscalEventAggregate; -import org.springframework.jdbc.core.BatchPreparedStatementSetter; -import org.springframework.stereotype.Component; - -import java.math.BigInteger; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.List; - -@Component -public class FiscalEventAggregatedDataMapper implements BatchPreparedStatementSetter { - - private List fiscalEventAggregates = null; - - public FiscalEventAggregatedDataMapper(List fiscalEventAggregates) { - this.fiscalEventAggregates = fiscalEventAggregates; - } - - @Override - public void setValues(PreparedStatement ps, int i) throws SQLException { - FiscalEventAggregate fiscalEventAggregate = fiscalEventAggregates.get(i); - - ps.setString(1, fiscalEventAggregate.getVer()); - ps.setString(2, fiscalEventAggregate.getTenantId()); - ps.setString(3, fiscalEventAggregate.getGovernment_id()); - ps.setString(4, fiscalEventAggregate.getGovernment_name()); - ps.setString(5, fiscalEventAggregate.getType()); - ps.setBigDecimal(6, fiscalEventAggregate.getSumAmount()); - ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); - ps.setLong(8, Long.parseLong(fiscalEventAggregate.getCount()!=null ? fiscalEventAggregate.getCount().toString() : "0")); - ps.setString(9, fiscalEventAggregate.getDepartment_id()); - ps.setString(10, fiscalEventAggregate.getDepartment_code()); - ps.setString(11, fiscalEventAggregate.getDepartment_name()); - - ps.setString(12, fiscalEventAggregate.getExpenditure_id()); - ps.setString(13, fiscalEventAggregate.getExpenditure_code()); - ps.setString(14, fiscalEventAggregate.getExpenditure_name()); - ps.setString(15, fiscalEventAggregate.getExpenditure_type()); - - ps.setString(16, fiscalEventAggregate.getProject_id()); - ps.setString(17, fiscalEventAggregate.getProject_code()); - ps.setString(18, fiscalEventAggregate.getProject_name()); - - ps.setString(19, fiscalEventAggregate.getCoa_id()); - ps.setString(20, fiscalEventAggregate.getCoa_coaCode()); - ps.setString(21, fiscalEventAggregate.getCoa_majorHead()); - ps.setString(22, fiscalEventAggregate.getCoa_majorHeadName()); - ps.setString(23, fiscalEventAggregate.getCoa_majorHeadType()); - ps.setString(24, fiscalEventAggregate.getCoa_subMajorHead()); - ps.setString(25, fiscalEventAggregate.getCoa_subMajorHeadName()); - ps.setString(26, fiscalEventAggregate.getCoa_minorHead()); - ps.setString(27, fiscalEventAggregate.getCoa_minorHeadName()); - ps.setString(28, fiscalEventAggregate.getCoa_subHead()); - ps.setString(29, fiscalEventAggregate.getCoa_subHeadName()); - ps.setString(30, fiscalEventAggregate.getCoa_groupHead()); - ps.setString(31, fiscalEventAggregate.getCoa_groupHeadName()); - ps.setString(32, fiscalEventAggregate.getCoa_objectHead()); - ps.setString(33, fiscalEventAggregate.getCoa_objectHeadName()); - - ps.setString(34, fiscalEventAggregate.getDepartmentEntity_ancestry_0_id()); - ps.setString(35, fiscalEventAggregate.getDepartmentEntity_ancestry_0_code()); - ps.setString(36, fiscalEventAggregate.getDepartmentEntity_ancestry_0_name()); - ps.setInt(37, fiscalEventAggregate.getDepartmentEntity_ancestry_0_hierarchyLevel()); - - - ps.setString(38, fiscalEventAggregate.getDepartmentEntity_ancestry_1_id()); - ps.setString(39, fiscalEventAggregate.getDepartmentEntity_ancestry_1_code()); - ps.setString(40, fiscalEventAggregate.getDepartmentEntity_ancestry_1_name()); - ps.setInt(41, fiscalEventAggregate.getDepartmentEntity_ancestry_1_hierarchyLevel()); - - ps.setString(42, fiscalEventAggregate.getDepartmentEntity_ancestry_2_id()); - ps.setString(43, fiscalEventAggregate.getDepartmentEntity_ancestry_2_code()); - ps.setString(44, fiscalEventAggregate.getDepartmentEntity_ancestry_2_name()); - ps.setInt(45, fiscalEventAggregate.getDepartmentEntity_ancestry_2_hierarchyLevel()); - - ps.setString(46, fiscalEventAggregate.getDepartmentEntity_ancestry_3_id()); - ps.setString(47, fiscalEventAggregate.getDepartmentEntity_ancestry_3_code()); - ps.setString(48, fiscalEventAggregate.getDepartmentEntity_ancestry_3_name()); - ps.setInt(49, fiscalEventAggregate.getDepartmentEntity_ancestry_3_hierarchyLevel()); - - ps.setString(50, fiscalEventAggregate.getDepartmentEntity_ancestry_4_id()); - ps.setString(51, fiscalEventAggregate.getDepartmentEntity_ancestry_4_code()); - ps.setString(52, fiscalEventAggregate.getDepartmentEntity_ancestry_4_name()); - ps.setInt(53, fiscalEventAggregate.getDepartmentEntity_ancestry_4_hierarchyLevel()); - - ps.setString(54, fiscalEventAggregate.getDepartmentEntity_ancestry_5_id()); - ps.setString(55, fiscalEventAggregate.getDepartmentEntity_ancestry_5_code()); - ps.setString(56, fiscalEventAggregate.getDepartmentEntity_ancestry_5_name()); - ps.setInt(57, fiscalEventAggregate.getDepartmentEntity_ancestry_5_hierarchyLevel()); - - ps.setString(58, fiscalEventAggregate.getDepartmentEntity_ancestry_6_id()); - ps.setString(59, fiscalEventAggregate.getDepartmentEntity_ancestry_6_code()); - ps.setString(60, fiscalEventAggregate.getDepartmentEntity_ancestry_6_name()); - ps.setInt(61, fiscalEventAggregate.getDepartmentEntity_ancestry_6_hierarchyLevel()); - - ps.setString(62, fiscalEventAggregate.getDepartmentEntity_ancestry_7_id()); - ps.setString(63, fiscalEventAggregate.getDepartmentEntity_ancestry_7_code()); - ps.setString(64, fiscalEventAggregate.getDepartmentEntity_ancestry_7_name()); - ps.setInt(65, fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() - : 7); - - ps.setString(66, fiscalEventAggregate.getDepartmentEntity_ancestry_8_id()); - ps.setString(67, fiscalEventAggregate.getDepartmentEntity_ancestry_8_code()); - ps.setString(68, fiscalEventAggregate.getDepartmentEntity_ancestry_8_name()); - ps.setInt(69, fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() : 8); - - ps.setString(70, fiscalEventAggregate.getDepartmentEntity_ancestry_9_id()); - ps.setString(71, fiscalEventAggregate.getDepartmentEntity_ancestry_9_code()); - ps.setString(72, fiscalEventAggregate.getDepartmentEntity_ancestry_9_name()); - ps.setInt(73, fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() : 9); - - ps.setString(74, fiscalEventAggregate.getDepartmentEntity_ancestry_10_id()); - ps.setString(75, fiscalEventAggregate.getDepartmentEntity_ancestry_10_code()); - ps.setString(76, fiscalEventAggregate.getDepartmentEntity_ancestry_10_name()); - ps.setInt(77, fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() : 10); - - - ps.setString(78, fiscalEventAggregate.getDepartmentEntity_id()); - ps.setString(79, fiscalEventAggregate.getDepartmentEntity_code()); - ps.setString(80, fiscalEventAggregate.getDepartmentEntity_name()); - ps.setInt(81, fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() : 0); - - - - //Update on conflict - ps.setString(82, fiscalEventAggregate.getVer()); - ps.setString(83, fiscalEventAggregate.getTenantId()); - ps.setString(84, fiscalEventAggregate.getGovernment_id()); - ps.setString(85, fiscalEventAggregate.getGovernment_name()); - //ps.setString(5, fiscalEventAggregate.getEventType()); - ps.setBigDecimal(86, fiscalEventAggregate.getSumAmount()); - //ps.setString(7, fiscalEventAggregate.getFiscalPeriod()); - ps.setLong(87, Long.parseLong(fiscalEventAggregate.getCount()!=null ? fiscalEventAggregate.getCount().toString() : "0"));// - ps.setString(88, fiscalEventAggregate.getDepartment_id()); - ps.setString(89, fiscalEventAggregate.getDepartment_code()); - ps.setString(90, fiscalEventAggregate.getDepartment_name()); - - ps.setString(91, fiscalEventAggregate.getExpenditure_id()); - ps.setString(92, fiscalEventAggregate.getExpenditure_code()); - ps.setString(93, fiscalEventAggregate.getExpenditure_name()); - ps.setString(94, fiscalEventAggregate.getExpenditure_type()); - - //ps.setString(91, fiscalEventAggregate.getProject_id()); - ps.setString(95, fiscalEventAggregate.getProject_code()); - ps.setString(96, fiscalEventAggregate.getProject_name()); - - //ps.setString(19, fiscalEventAggregate.getCoa_id()); - ps.setString(97, fiscalEventAggregate.getCoa_coaCode()); - ps.setString(98, fiscalEventAggregate.getCoa_majorHead()); - ps.setString(99, fiscalEventAggregate.getCoa_majorHeadName()); - ps.setString(100, fiscalEventAggregate.getCoa_majorHeadType()); - ps.setString(101, fiscalEventAggregate.getCoa_subMajorHead()); - ps.setString(102, fiscalEventAggregate.getCoa_subMajorHeadName()); - ps.setString(103, fiscalEventAggregate.getCoa_minorHead()); - ps.setString(104, fiscalEventAggregate.getCoa_minorHeadName()); - ps.setString(105, fiscalEventAggregate.getCoa_subHead()); - ps.setString(106, fiscalEventAggregate.getCoa_subHeadName()); - ps.setString(107, fiscalEventAggregate.getCoa_groupHead()); - ps.setString(108, fiscalEventAggregate.getCoa_groupHeadName()); - ps.setString(109, fiscalEventAggregate.getCoa_objectHead()); - ps.setString(110, fiscalEventAggregate.getCoa_objectHeadName()); - - ps.setString(111, fiscalEventAggregate.getDepartmentEntity_ancestry_0_id()); - ps.setString(112, fiscalEventAggregate.getDepartmentEntity_ancestry_0_code()); - ps.setString(113, fiscalEventAggregate.getDepartmentEntity_ancestry_0_name()); - ps.setInt(114, fiscalEventAggregate.getDepartmentEntity_ancestry_0_hierarchyLevel()); - - - ps.setString(115, fiscalEventAggregate.getDepartmentEntity_ancestry_1_id()); - ps.setString(116, fiscalEventAggregate.getDepartmentEntity_ancestry_1_code()); - ps.setString(117, fiscalEventAggregate.getDepartmentEntity_ancestry_1_name()); - ps.setInt(118, fiscalEventAggregate.getDepartmentEntity_ancestry_1_hierarchyLevel()); - - ps.setString(119, fiscalEventAggregate.getDepartmentEntity_ancestry_2_id()); - ps.setString(120, fiscalEventAggregate.getDepartmentEntity_ancestry_2_code()); - ps.setString(121, fiscalEventAggregate.getDepartmentEntity_ancestry_2_name()); - ps.setInt(122, fiscalEventAggregate.getDepartmentEntity_ancestry_2_hierarchyLevel()); - - ps.setString(123, fiscalEventAggregate.getDepartmentEntity_ancestry_3_id()); - ps.setString(124, fiscalEventAggregate.getDepartmentEntity_ancestry_3_code()); - ps.setString(125, fiscalEventAggregate.getDepartmentEntity_ancestry_3_name()); - ps.setInt(126, fiscalEventAggregate.getDepartmentEntity_ancestry_3_hierarchyLevel()); - - ps.setString(127, fiscalEventAggregate.getDepartmentEntity_ancestry_4_id()); - ps.setString(128, fiscalEventAggregate.getDepartmentEntity_ancestry_4_code()); - ps.setString(129, fiscalEventAggregate.getDepartmentEntity_ancestry_4_name()); - ps.setInt(130, fiscalEventAggregate.getDepartmentEntity_ancestry_4_hierarchyLevel()); - - ps.setString(131, fiscalEventAggregate.getDepartmentEntity_ancestry_5_id()); - ps.setString(132, fiscalEventAggregate.getDepartmentEntity_ancestry_5_code()); - ps.setString(133, fiscalEventAggregate.getDepartmentEntity_ancestry_5_name()); - ps.setInt(134, fiscalEventAggregate.getDepartmentEntity_ancestry_5_hierarchyLevel()); - - ps.setString(135, fiscalEventAggregate.getDepartmentEntity_ancestry_6_id()); - ps.setString(136, fiscalEventAggregate.getDepartmentEntity_ancestry_6_code()); - ps.setString(137, fiscalEventAggregate.getDepartmentEntity_ancestry_6_name()); - ps.setInt(138, fiscalEventAggregate.getDepartmentEntity_ancestry_6_hierarchyLevel()); - - ps.setString(139, fiscalEventAggregate.getDepartmentEntity_ancestry_7_id()); - ps.setString(140, fiscalEventAggregate.getDepartmentEntity_ancestry_7_code()); - ps.setString(141, fiscalEventAggregate.getDepartmentEntity_ancestry_7_name()); - ps.setInt(142, fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_7_hierarchyLevel() - : 7); - - ps.setString(143, fiscalEventAggregate.getDepartmentEntity_ancestry_8_id()); - ps.setString(144, fiscalEventAggregate.getDepartmentEntity_ancestry_8_code()); - ps.setString(145, fiscalEventAggregate.getDepartmentEntity_ancestry_8_name()); - ps.setInt(146, fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_8_hierarchyLevel() : 8); - - ps.setString(147, fiscalEventAggregate.getDepartmentEntity_ancestry_9_id()); - ps.setString(148, fiscalEventAggregate.getDepartmentEntity_ancestry_9_code()); - ps.setString(149, fiscalEventAggregate.getDepartmentEntity_ancestry_9_name()); - ps.setInt(150, fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_9_hierarchyLevel() : 9); - - ps.setString(151, fiscalEventAggregate.getDepartmentEntity_ancestry_10_id()); - ps.setString(152, fiscalEventAggregate.getDepartmentEntity_ancestry_10_code()); - ps.setString(153, fiscalEventAggregate.getDepartmentEntity_ancestry_10_name()); - ps.setInt(154, fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_ancestry_10_hierarchyLevel() : 10); - - ps.setString(155, fiscalEventAggregate.getDepartmentEntity_id()); - ps.setString(156, fiscalEventAggregate.getDepartmentEntity_code()); - ps.setString(157, fiscalEventAggregate.getDepartmentEntity_name()); - ps.setInt(158, fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() != null - ? fiscalEventAggregate.getDepartmentEntity_hierarchyLevel() : 0); - } - - @Override - public int getBatchSize() { - return fiscalEventAggregates.size(); - } -} From 208beec6a4339aba8b4761637e468e4f023c9b01 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Tue, 23 Nov 2021 11:10:03 +0530 Subject: [PATCH 66/67] removed commented code --- .../mapper/FiscalEventAggregateQuery.java | 23 ------------------- .../src/main/resources/application.properties | 2 +- 2 files changed, 1 insertion(+), 24 deletions(-) diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java index 910cfcdc..2a360fe4 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java +++ b/reference-dashboard/fiscal-event-aggregator/src/main/java/org/egov/ifix/aggregate/repository/mapper/FiscalEventAggregateQuery.java @@ -76,27 +76,4 @@ public class FiscalEventAggregateQuery { "departmentEntity_ancestry_10_code=:departmentEntity_ancestry_10_code,departmentEntity_ancestry_10_name=:departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel=:departmentEntity_ancestry_10_hierarchyLevel," + "departmentEntity_id=:departmentEntity_id,departmentEntity_code=:departmentEntity_code,departmentEntity_name=:departmentEntity_name,departmentEntity_hierarchyLevel=:departmentEntity_hierarchyLevel;"; -// public static final String INSERT_QUERY_FOR_FISCAL_EVENT_AGGREGATE = "INSERT INTO fiscal_event_aggregated" + -// "(ver,tenantId,government_id,government_name,type,sumAmount,fiscalPeriod,count,department_id,department_code," + -// "department_name,expenditure_id,expenditure_code,expenditure_name,expenditure_type,project_id,project_code,project_name,coa_id,coa_coaCode,coa_majorHead,coa_majorHeadName," + -// "coa_majorHeadType,coa_subMajorHead,coa_subMajorHeadName,coa_minorHead,coa_minorHeadName,coa_subHead,coa_subHeadName," + -// "coa_groupHead,coa_groupHeadName,coa_objectHead,coa_objectHeadName," + -// "departmentEntity_ancestry_0_id,departmentEntity_ancestry_0_code,departmentEntity_ancestry_0_name,"+ -// "departmentEntity_ancestry_0_hierarchyLevel,departmentEntity_ancestry_1_id,departmentEntity_ancestry_1_code,"+ -// "departmentEntity_ancestry_1_name,departmentEntity_ancestry_1_hierarchyLevel,departmentEntity_ancestry_2_id," + -// "departmentEntity_ancestry_2_code,departmentEntity_ancestry_2_name,departmentEntity_ancestry_2_hierarchyLevel," + -// "departmentEntity_ancestry_3_id,departmentEntity_ancestry_3_code,departmentEntity_ancestry_3_name," + -// "departmentEntity_ancestry_3_hierarchyLevel,departmentEntity_ancestry_4_id,departmentEntity_ancestry_4_code," + -// "departmentEntity_ancestry_4_name,departmentEntity_ancestry_4_hierarchyLevel,departmentEntity_ancestry_5_id," + -// "departmentEntity_ancestry_5_code,departmentEntity_ancestry_5_name,departmentEntity_ancestry_5_hierarchyLevel," + -// "departmentEntity_ancestry_6_id,departmentEntity_ancestry_6_code,departmentEntity_ancestry_6_name," + -// "departmentEntity_ancestry_6_hierarchyLevel,departmentEntity_ancestry_7_id,departmentEntity_ancestry_7_code," + -// "departmentEntity_ancestry_7_name,departmentEntity_ancestry_7_hierarchyLevel,departmentEntity_ancestry_8_id," + -// "departmentEntity_ancestry_8_code,departmentEntity_ancestry_8_name,departmentEntity_ancestry_8_hierarchyLevel," + -// "departmentEntity_ancestry_9_id,departmentEntity_ancestry_9_code,departmentEntity_ancestry_9_name," + -// "departmentEntity_ancestry_9_hierarchyLevel,departmentEntity_ancestry_10_id,departmentEntity_ancestry_10_code," + -// "departmentEntity_ancestry_10_name,departmentEntity_ancestry_10_hierarchyLevel) " + -// "VALUES" + -// "(?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?," + -// "?,?,?,?,?,?,?,?,?,?,?,?,?,?,?) ;" ; } diff --git a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties index d1275979..1c0bbe63 100644 --- a/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties +++ b/reference-dashboard/fiscal-event-aggregator/src/main/resources/application.properties @@ -7,7 +7,7 @@ spring.datasource.username=postgres spring.datasource.password=root ## Druid Config ## -druid.host=druid-qa.ifix.org.in +druid.host=druid-dev.digit.org druid.endPoint=druid/v2/ fiscal.event.datasource=fiscal-event druid.connect.protocol=HTTPS From 93699327edd936404a21a7d7a0e0f2c82e1586a5 Mon Sep 17 00:00:00 2001 From: pintu-eGov Date: Tue, 23 Nov 2021 13:27:41 +0530 Subject: [PATCH 67/67] removed unused test file --- ...iscalEventAggregatorServiceApplicationTests.java | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java diff --git a/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java b/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java deleted file mode 100644 index 1bf1ea9a..00000000 --- a/reference-dashboard/fiscal-event-aggregator/src/test/java/org/egov/ifix/aggregate/FiscalEventAggregatorServiceApplicationTests.java +++ /dev/null @@ -1,13 +0,0 @@ -package org.egov.ifix.aggregate; - -import org.junit.jupiter.api.Test; -import org.springframework.boot.test.context.SpringBootTest; - -@SpringBootTest -class FiscalEventAggregatorServiceApplicationTests { - -// @Test -// void contextLoads() { -// } - -}