diff --git a/CODEOWNERS b/CODEOWNERS
index 30885762527..7833b872775 100644
--- a/CODEOWNERS
+++ b/CODEOWNERS
@@ -1,3 +1,3 @@
* @kavi-egov @sathishp-eGov
-health-services/project-factory/ @jagankumar-egov
+health-services/project-factory/ @jagankumar-egov
diff --git a/core-services/service-request/pom.xml b/core-services/service-request/pom.xml
index 5b5bfe71423..f04bced991b 100644
--- a/core-services/service-request/pom.xml
+++ b/core-services/service-request/pom.xml
@@ -43,7 +43,7 @@
org.flywaydb
flyway-core
- 9.22.3
+
org.postgresql
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java b/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java
index 2d5b8f71444..4aa6a5d519b 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/config/Configuration.java
@@ -55,6 +55,9 @@ public MappingJackson2HttpMessageConverter jacksonConverter(ObjectMapper objectM
@Value("${egov.service.definition.create.topic}")
private String serviceDefinitionCreateTopic;
+ @Value("${egov.service.definition.update.topic}")
+ private String serviceDefinitionUpdateTopic;
+
@Value("${egov.service.create.topic}")
private String serviceCreateTopic;
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java
index 754e55208bb..e1a99338c3c 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/error/ErrorCode.java
@@ -1,6 +1,7 @@
package org.egov.servicerequest.error;
import org.springframework.stereotype.Component;
+import org.apache.kafka.common.protocol.types.Field;
@Component
public class ErrorCode {
@@ -30,6 +31,8 @@ public class ErrorCode {
public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG = "Attribute Value provided against the attribute definition of type multi value list must be an instance of list";
+ public static final String SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG = "Attribute Value provided against the attribute definition of type boolean must be an instance of boolean";
+
public static final String INVALID_SIZE_OF_INPUT_CODE = "INVALID_SIZE_OF_INPUT_CODE";
public static final String INVALID_SIZE_OF_TEXT_MSG = "Text value cannot be of length greater than configured length ";
@@ -61,4 +64,17 @@ public class ErrorCode {
public static final String INVALID_REGEX_ERR_CODE = "INVALID_REGEX_ERR_CODE";
public static final String INVALID_REGEX_ERR_MSG = "The provided regex failed to compile for attribute definition with code - ";
+
+ public static final String SERVICE_DEFINITION_NOT_EXIST_ERR_CODE = "SERVICE_DEFINITION_NOT_EXIST_ERR_CODE";
+
+ public static final String SERVICE_DEFINITION_NOT_EXIST_ERR_MSG = "Provided tenantId and code unique combination does not exist";
+
+ public static final String VALID_SERVICE_EXIST_ERR_CODE = "VALID_SERVICE_EXIST_ERR_CODE";
+
+ public static final String VALID_SERVICE_EXIST_ERR_MSG = "Valid Service exists corresponding to Service Definition";
+
+ public static final String INACTIVE_SERVICE_DEFINITION_ERR_CODE = "INACTIVE_SERVICE_DEFINITION_ERR_CODE";
+
+ public static final String INACTIVE_SERVICE_DEFINITION_ERR_MSG = "Inactive Service Definition cannot be updated";
+
}
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java
index afd7c2ef680..feabdbba147 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/repository/querybuilder/ServiceDefinitionQueryBuilder.java
@@ -56,9 +56,11 @@ public String getServiceDefinitionsIdsQuery(ServiceDefinitionSearchRequest servi
}
// Fetch service definitions which have NOT been soft deleted
- addClauseIfRequired(query, preparedStmtList);
- query.append(" sd.isActive = ? ");
- preparedStmtList.add(Boolean.TRUE);
+ if(!serviceDefinitionSearchRequest.isIncludeDeleted()){
+ addClauseIfRequired(query, preparedStmtList);
+ query.append(" sd.isActive = ? ");
+ preparedStmtList.add(Boolean.TRUE);
+ }
// order service definitions based on their createdtime in latest first manner
query.append(ORDERBY_CREATEDTIME);
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java
index 185274a0eae..64c3c52b6ea 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceDefinitionRequestService.java
@@ -68,7 +68,19 @@ public List searchServiceDefinition(ServiceDefinitionSearchRe
public ServiceDefinition updateServiceDefinition(ServiceDefinitionRequest serviceDefinitionRequest) {
- // TO DO
+ ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition();
+
+ //Validate incoming service definition request
+ ServiceDefinition definitionFromDb = serviceDefinitionRequestValidator.validateUpdateRequest(serviceDefinitionRequest);
+
+ //Enrich incoming service definition request
+ enrichmentService.enrichServiceDefinitionUpdateRequest(serviceDefinitionRequest, definitionFromDb);
+
+ // Producer statement to emit service definition to kafka for persisting
+ producer.push(config.getServiceDefinitionUpdateTopic(), serviceDefinitionRequest);
+
+ // Restore attribute values to the type in which it was sent in service definition request
+ enrichmentService.setAttributeDefinitionValuesBackToNativeState(serviceDefinition);
return serviceDefinitionRequest.getServiceDefinition();
}
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java
index 90b9729f864..0864c204d42 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/service/ServiceRequestEnrichmentService.java
@@ -15,6 +15,7 @@
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import java.util.stream.Collectors;
@Component
public class ServiceRequestEnrichmentService {
@@ -110,4 +111,68 @@ public void setAttributeValuesBackToNativeState(ServiceRequest serviceRequest, M
attributeValue.setValue(attributeCodeVsValueMap.get(attributeValue.getAttributeCode()));
});
}
+
+ private void updateAttributeDefinition(AttributeDefinition attributeDefinition, AttributeDefinition existingAttributeDefinition, RequestInfo requestInfo){
+
+ attributeDefinition.setId(existingAttributeDefinition.getId());
+
+ attributeDefinition.setAuditDetails(existingAttributeDefinition.getAuditDetails());
+
+ attributeDefinition.setReferenceId(existingAttributeDefinition.getReferenceId());
+
+ attributeDefinition.getAuditDetails().setLastModifiedTime(System.currentTimeMillis());
+
+ attributeDefinition.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUuid());
+
+ }
+ private void upsertAttributeDefinition(AttributeDefinition attributeDefinition, ServiceDefinitionRequest serviceDefinitionRequest){
+ RequestInfo requestInfo = serviceDefinitionRequest.getRequestInfo();
+
+ attributeDefinition.setId(UUID.randomUUID().toString());
+
+ attributeDefinition.setAuditDetails(
+ AuditDetails.builder()
+ .createdBy(requestInfo.getUserInfo().getUuid())
+ .createdTime(System.currentTimeMillis())
+ .lastModifiedBy(requestInfo.getUserInfo().getUuid())
+ .lastModifiedTime(System.currentTimeMillis())
+ .build()
+ );
+
+ attributeDefinition.setReferenceId(serviceDefinitionRequest.getServiceDefinition().getId());
+ }
+ public void enrichServiceDefinitionUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest, ServiceDefinition definitionFromDb) {
+ List attributeDefinitions = serviceDefinitionRequest.getServiceDefinition().getAttributes();
+
+ //For quick lookup of Attribute Definition with Code
+ Map existingAttributeCode = definitionFromDb
+ .getAttributes()
+ .stream()
+ .collect(Collectors.toMap(AttributeDefinition::getCode, a->a));
+
+ RequestInfo requestInfo = serviceDefinitionRequest.getRequestInfo();
+
+ ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition();
+
+ serviceDefinition.setId(definitionFromDb.getId());
+ serviceDefinition.setAuditDetails(definitionFromDb.getAuditDetails());
+ serviceDefinition.getAuditDetails().setLastModifiedBy(requestInfo.getUserInfo().getUuid());
+ serviceDefinition.getAuditDetails().setLastModifiedTime(System.currentTimeMillis());
+
+ attributeDefinitions.forEach(attributeDefinition -> {
+ if(existingAttributeCode.containsKey(attributeDefinition.getCode())){
+ updateAttributeDefinition(attributeDefinition, existingAttributeCode.get(attributeDefinition.getCode()), requestInfo);
+ }
+ else{
+ upsertAttributeDefinition(attributeDefinition, serviceDefinitionRequest);
+ }
+
+ if(!(attributeDefinition.getDataType().equals(AttributeDefinition.DataTypeEnum.SINGLEVALUELIST) || attributeDefinition.getDataType().equals(AttributeDefinition.DataTypeEnum.MULTIVALUELIST))){
+ List emptyStringList = new ArrayList<>();
+ emptyStringList.add("");
+ attributeDefinition.setValues(emptyStringList);
+ }
+ });
+
+ }
}
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java
index 86f8debd558..d8e13c5ea69 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceDefinitionRequestValidator.java
@@ -1,11 +1,8 @@
package org.egov.servicerequest.validators;
import org.egov.servicerequest.repository.ServiceDefinitionRequestRepository;
-import org.egov.servicerequest.web.models.AttributeDefinition;
-import org.egov.servicerequest.web.models.ServiceDefinition;
-import org.egov.servicerequest.web.models.ServiceDefinitionCriteria;
-import org.egov.servicerequest.web.models.ServiceDefinitionRequest;
-import org.egov.servicerequest.web.models.ServiceDefinitionSearchRequest;
+import org.egov.servicerequest.repository.ServiceRequestRepository;
+import org.egov.servicerequest.web.models.*;
import org.egov.tracer.model.CustomException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@@ -18,14 +15,7 @@
import java.util.Set;
import java.util.regex.Pattern;
-import static org.egov.servicerequest.error.ErrorCode.ATTRIBUTE_CODE_UNIQUENESS_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.ATTRIBUTE_CODE_UNIQUENESS_ERR_MSG;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_ATTRIBUTE_DEFINITION_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_ATTRIBUTE_DEFINITION_ERR_MSG;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_REGEX_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_REGEX_ERR_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_DEFINITION_ALREADY_EXISTS_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_DEFINITION_ALREADY_EXISTS_ERR_MSG;
+import static org.egov.servicerequest.error.ErrorCode.*;
@Component
public class ServiceDefinitionRequestValidator {
@@ -33,6 +23,10 @@ public class ServiceDefinitionRequestValidator {
@Autowired
private ServiceDefinitionRequestRepository serviceDefinitionRequestRepository;
+ @Autowired
+ private ServiceRequestRepository serviceRequestRepository;
+
+
public void validateServiceDefinitionRequest(ServiceDefinitionRequest serviceDefinitionRequest){
ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition();
@@ -87,16 +81,57 @@ private void validateAttributeDefinitionUniqueness(ServiceDefinition serviceDefi
}
private void validateServiceDefinitionExistence(ServiceDefinition serviceDefinition) {
- List serviceDefinitionList = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build());
+ List serviceDefinitionList = serviceDefinitionRequestRepository.getServiceDefinitions(ServiceDefinitionSearchRequest.builder().includeDeleted(true).serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build());
if(!CollectionUtils.isEmpty(serviceDefinitionList)){
throw new CustomException(SERVICE_DEFINITION_ALREADY_EXISTS_ERR_CODE, SERVICE_DEFINITION_ALREADY_EXISTS_ERR_MSG);
}
}
- public void validateUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest) {
+ private List validateExistence(ServiceDefinition serviceDefinition) {
+ List serviceDefinitionList = serviceDefinitionRequestRepository.
+ getServiceDefinitions(ServiceDefinitionSearchRequest.builder()
+ .includeDeleted(true)
+ .serviceDefinitionCriteria(ServiceDefinitionCriteria.builder().tenantId(serviceDefinition.getTenantId()).code(Collections.singletonList(serviceDefinition.getCode())).build()).build());
+
+ //Check if valid service definition exists
+ if (CollectionUtils.isEmpty(serviceDefinitionList)) {
+ throw new CustomException(SERVICE_DEFINITION_NOT_EXIST_ERR_CODE, SERVICE_DEFINITION_NOT_EXIST_ERR_MSG);
+ }
+
+ return serviceDefinitionList;
+ }
+
+ private void validateService(List serviceDefinition){
+ List service = serviceRequestRepository.getService(
+ ServiceSearchRequest.builder().serviceCriteria(
+ ServiceCriteria.builder().serviceDefIds(Collections.singletonList(serviceDefinition.get(0).getId())).build()
+ ).build()
+ );
+ //already a service exists corresponding to service definition
+ if(!CollectionUtils.isEmpty(service)){
+ throw new CustomException(VALID_SERVICE_EXIST_ERR_CODE, VALID_SERVICE_EXIST_ERR_MSG);
+ }
+ }
+
+ public ServiceDefinition validateUpdateRequest(ServiceDefinitionRequest serviceDefinitionRequest) {
+ ServiceDefinition serviceDefinition = serviceDefinitionRequest.getServiceDefinition();
+
+ //Validate if a Service Definition exists
+ List serviceDefinitionList = validateExistence(serviceDefinition);
+
+ //Validate if a Service exists corresponding to this Service Definition
+ validateService(serviceDefinitionList);
+
+ // Validate if all attribute definitions provided as part of service definitions have unique code
+ validateAttributeDefinitionUniqueness(serviceDefinition);
- // TO DO
+ // Validate values provided in attribute definitions as per data type
+ validateAttributeValuesAsPerDataType(serviceDefinition);
+
+ // Validate regex values provided in attribute definitions
+ validateRegex(serviceDefinition);
+ return serviceDefinitionList.get(0);
}
}
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java
index 66595568bc1..67b2929b36d 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/validators/ServiceRequestValidator.java
@@ -21,25 +21,7 @@
import java.util.Map;
import java.util.Set;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_INPUT_CODE;
-import static org.egov.servicerequest.error.ErrorCode.INVALID_SIZE_OF_TEXT_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_DATETIME_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_NUMBER_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_SINGLE_VALUE_LIST_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_STRING_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_TEXT_VALUE_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_MULTIVALUELIST_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_SINGLEVALUELIST_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_ATTRIBUTE_VALUES_UNIQUENESS_ERR_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_INVALID_SERVICE_DEF_ID_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_REQUIRED_ATTRIBUTE_NOT_PROVIDED_ERR_MSG;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_CODE;
-import static org.egov.servicerequest.error.ErrorCode.SERVICE_REQUEST_UNRECOGNIZED_ATTRIBUTE_MSG;
+import static org.egov.servicerequest.error.ErrorCode.*;
@Slf4j
@Component
@@ -133,6 +115,10 @@ private void validateAttributeValuesAgainstServiceDefinition(ServiceDefinition s
if(!(attributeValue.getValue() instanceof List)){
throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_MULTI_VALUE_LIST_VALUE_MSG);
}
+ }else if(attributeCodeVsDataType.get(attributeValue.getAttributeCode()).equals(AttributeDefinition.DataTypeEnum.BOOLEAN)){
+ if(!(attributeValue.getValue() instanceof Boolean)){
+ throw new CustomException(SERVICE_REQUEST_ATTRIBUTE_INVALID_VALUE_CODE, SERVICE_REQUEST_ATTRIBUTE_INVALID_BOOLEAN_VALUE_MSG);
+ }
}
});
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java
index 59c32cf913b..649421350a1 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeDefinition.java
@@ -41,7 +41,7 @@ public class AttributeDefinition {
@JsonProperty("code")
@NotNull
- @Size(min = 2, max = 64)
+ @Size(min = 2, max = 256)
private String code = null;
/**
@@ -50,6 +50,8 @@ public class AttributeDefinition {
public enum DataTypeEnum {
STRING("String"),
+ BOOLEAN("Boolean"),
+
NUMBER("Number"),
TEXT("Text"),
@@ -60,9 +62,7 @@ public enum DataTypeEnum {
MULTIVALUELIST("MultiValueList"),
- FILE("File"),
-
- BOOLEAN("Boolean");
+ FILE("File");
private String value;
@@ -112,7 +112,7 @@ public static DataTypeEnum fromValue(String text) {
@Valid
private AuditDetails auditDetails = null;
- @JsonProperty("additionalDetails")
+ @JsonProperty("additionalFields")
private Object additionalDetails = null;
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java
index 8aeff4e39f3..98ce105e9b3 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/AttributeValue.java
@@ -41,7 +41,7 @@ public class AttributeValue {
@Valid
private AuditDetails auditDetails = null;
- @JsonProperty("additionalDetails")
+ @JsonProperty("additionalFields")
private Object additionalDetails = null;
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java
index b0348458c15..4fc646ca8ea 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/Service.java
@@ -51,7 +51,7 @@ public class Service {
@Valid
private AuditDetails auditDetails = null;
- @JsonProperty("additionalDetails")
+ @JsonProperty("additionalFields")
private Object additionalDetails = null;
@JsonProperty("accountId")
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java
index e91eeedf541..01b9b31fac9 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinition.java
@@ -35,7 +35,7 @@ public class ServiceDefinition {
@JsonProperty("code")
@NotNull
- @Size(min = 2, max = 64)
+ @Size(min = 2, max = 256)
private String code = null;
@JsonProperty("isActive")
@@ -50,7 +50,7 @@ public class ServiceDefinition {
@Valid
private AuditDetails auditDetails = null;
- @JsonProperty("additionalDetails")
+ @JsonProperty("additionalFields")
private Object additionalDetails = null;
@JsonProperty("clientId")
diff --git a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java
index 82af972de54..1971656a6c8 100644
--- a/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java
+++ b/core-services/service-request/src/main/java/org/egov/servicerequest/web/models/ServiceDefinitionSearchRequest.java
@@ -33,5 +33,6 @@ public class ServiceDefinitionSearchRequest {
@Valid
private Pagination pagination = null;
-
+ @JsonProperty("includeDeleted")
+ private boolean includeDeleted = false;
}
diff --git a/core-services/service-request/src/main/resources/application.properties b/core-services/service-request/src/main/resources/application.properties
index b08e73fc128..a3fdc45c3f2 100644
--- a/core-services/service-request/src/main/resources/application.properties
+++ b/core-services/service-request/src/main/resources/application.properties
@@ -48,6 +48,7 @@ egov.service.request.max.limit=100
# Kafka topics
egov.service.definition.create.topic=save-service-definition
egov.service.create.topic=save-service
+egov.service.definition.update.topic=update-service-definition
# String input size configuration
egov.max.string.input.size=8192
\ No newline at end of file
diff --git a/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql
new file mode 100644
index 00000000000..ed8ce4007ca
--- /dev/null
+++ b/core-services/service-request/src/main/resources/db/migration/main/V20241115143930__servicedefinition_alter_ddl.sql
@@ -0,0 +1,9 @@
+-- Migration script to alter the length of 'code' column in both tables to 256
+
+-- Update eg_service_definition table
+ALTER TABLE eg_service_definition
+ALTER COLUMN code TYPE character varying(256);
+
+-- Update eg_service_attribute_definition table
+ALTER TABLE eg_service_attribute_definition
+ALTER COLUMN code TYPE character varying(256);
diff --git a/core-services/service-request/src/main/resources/service-request-persister.yml b/core-services/service-request/src/main/resources/service-request-persister.yml
index 10fc9ce8702..22bcf13539c 100644
--- a/core-services/service-request/src/main/resources/service-request-persister.yml
+++ b/core-services/service-request/src/main/resources/service-request-persister.yml
@@ -8,72 +8,68 @@ serviceMaps:
queryMaps:
- query: INSERT INTO eg_service_definition(id, tenantid, code, isactive, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails, clientid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
- basePath: $.serviceDefinition
+ basePath: $.ServiceDefinition
jsonMaps:
- - jsonPath: $.serviceDefinition.id
+ - jsonPath: $.ServiceDefinition.id
- - jsonPath: $.serviceDefinition.tenantId
+ - jsonPath: $.ServiceDefinition.tenantId
- - jsonPath: $.serviceDefinition.code
+ - jsonPath: $.ServiceDefinition.code
- - jsonPath: $.serviceDefinition.isActive
+ - jsonPath: $.ServiceDefinition.isActive
- - jsonPath: $.serviceDefinition.auditDetails.createdBy
+ - jsonPath: $.ServiceDefinition.auditDetails.createdBy
- - jsonPath: $.serviceDefinition.auditDetails.lastModifiedBy
+ - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedBy
- - jsonPath: $.serviceDefinition.auditDetails.createdTime
+ - jsonPath: $.ServiceDefinition.auditDetails.createdTime
- - jsonPath: $.serviceDefinition.auditDetails.lastModifiedTime
+ - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedTime
- - jsonPath: $.serviceDefinition.additionalDetails
+ - jsonPath: $.ServiceDefinition.additionalDetails
type: JSON
dbType: JSONB
- - jsonPath: $.serviceDefinition.clientId
+ - jsonPath: $.ServiceDefinition.clientId
- query: INSERT INTO eg_service_attribute_definition(id, referenceid, tenantid, code, datatype, "values", isactive, required, regex, "order", createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
- basePath: $.serviceDefinition.attributes.*
+ basePath: $.ServiceDefinition.attributes.*
jsonMaps:
- - jsonPath: $.serviceDefinition.attributes.*.id
+ - jsonPath: $.ServiceDefinition.attributes.*.id
- - jsonPath: $.serviceDefinition.attributes.*.referenceId
+ - jsonPath: $.ServiceDefinition.attributes.*.referenceId
- - jsonPath: $.serviceDefinition.attributes.*.tenantId
+ - jsonPath: $.ServiceDefinition.attributes.*.tenantId
- - jsonPath: $.serviceDefinition.attributes.*.code
+ - jsonPath: $.ServiceDefinition.attributes.*.code
- - jsonPath: $.serviceDefinition.attributes.*.dataType
+ - jsonPath: $.ServiceDefinition.attributes.*.dataType
- - jsonPath: $.serviceDefinition.attributes.*.values
+ - jsonPath: $.ServiceDefinition.attributes.*.values
type: ARRAY
dbType: STRING
- - jsonPath: $.serviceDefinition.attributes.*.isActive
+ - jsonPath: $.ServiceDefinition.attributes.*.isActive
- - jsonPath: $.serviceDefinition.attributes.*.required
+ - jsonPath: $.ServiceDefinition.attributes.*.required
- - jsonPath: $.serviceDefinition.attributes.*.regex
+ - jsonPath: $.ServiceDefinition.attributes.*.regex
- - jsonPath: $.serviceDefinition.attributes.*.order
+ - jsonPath: $.ServiceDefinition.attributes.*.order
- - jsonPath: $.serviceDefinition.attributes.*.auditDetails.createdBy
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdBy
- - jsonPath: $.serviceDefinition.attributes.*.auditDetails.lastModifiedBy
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy
- - jsonPath: $.serviceDefinition.attributes.*.auditDetails.createdTime
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdTime
- - jsonPath: $.serviceDefinition.attributes.*.auditDetails.lastModifiedTime
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime
- - jsonPath: $.serviceDefinition.attributes.*.additionalDetails
+ - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails
type: JSON
dbType: JSONB
-
-
-
-
- version: 1.0
description: Persists service details in service table
fromTopic: save-service
@@ -82,54 +78,135 @@ serviceMaps:
- query: INSERT INTO eg_service(id, tenantid, servicedefid, referenceid, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails, accountid, clientid) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?);
- basePath: $.service
+ basePath: $.Service
jsonMaps:
- - jsonPath: $.service.id
+ - jsonPath: $.Service.id
- - jsonPath: $.service.tenantId
+ - jsonPath: $.Service.tenantId
- - jsonPath: $.service.serviceDefId
+ - jsonPath: $.Service.serviceDefId
- - jsonPath: $.service.referenceId
+ - jsonPath: $.Service.referenceId
- - jsonPath: $.service.auditDetails.createdBy
+ - jsonPath: $.Service.auditDetails.createdBy
- - jsonPath: $.service.auditDetails.lastModifiedBy
+ - jsonPath: $.Service.auditDetails.lastModifiedBy
- - jsonPath: $.service.auditDetails.createdTime
+ - jsonPath: $.Service.auditDetails.createdTime
- - jsonPath: $.service.auditDetails.lastModifiedTime
+ - jsonPath: $.Service.auditDetails.lastModifiedTime
- - jsonPath: $.service.additionalDetails
+ - jsonPath: $.Service.additionalDetails
type: JSON
dbType: JSONB
- - jsonPath: $.service.accountId
+ - jsonPath: $.Service.accountId
- - jsonPath: $.service.clientId
+ - jsonPath: $.Service.clientId
- query: INSERT INTO eg_service_attribute_value(id, referenceid, attributecode, value, createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?);
- basePath: $.service.attributes.*
+ basePath: $.Service.attributes.*
+ jsonMaps:
+ - jsonPath: $.Service.attributes.*.id
+
+ - jsonPath: $.Service.attributes.*.referenceId
+
+ - jsonPath: $.Service.attributes.*.attributeCode
+
+ - jsonPath: $.Service.attributes.*.value
+ type: JSON
+ dbType: JSONB
+
+ - jsonPath: $.Service.attributes.*.auditDetails.createdBy
+
+ - jsonPath: $.Service.attributes.*.auditDetails.lastModifiedBy
+
+ - jsonPath: $.Service.attributes.*.auditDetails.createdTime
+
+ - jsonPath: $.Service.attributes.*.auditDetails.lastModifiedTime
+
+ - jsonPath: $.Service.attributes.*.additionalDetails
+ type: JSON
+ dbType: JSONB
+
+
+ - version: 1.0
+ description: Update Service Definition
+ fromTopic: update-service-definition
+ isTransaction: true
+ queryMaps:
+
+ - query: UPDATE eg_service_definition SET lastmodifiedby = ?, lastmodifiedtime = ?, isactive = ?, additionaldetails = ? WHERE id = ?
+ basePath: $.ServiceDefinition
+ jsonMaps:
+ - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedBy
+
+ - jsonPath: $.ServiceDefinition.auditDetails.lastModifiedTime
+
+ - jsonPath: $.ServiceDefinition.isActive
+
+ - jsonPath: $.ServiceDefinition.additionalDetails
+ type: JSON
+ dbType: JSONB
+
+ - jsonPath: $.ServiceDefinition.id
+
+ - query: INSERT INTO eg_service_attribute_definition(id, referenceid, tenantid, code, datatype, "values", isactive, required, regex, "order", createdby, lastmodifiedby, createdtime, lastmodifiedtime, additionaldetails) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) ON CONFLICT (id) DO UPDATE SET datatype=?, "values"=?, isactive=?, required=?, regex=?, "order"=?, lastmodifiedby=?, lastmodifiedtime=?, additionaldetails=?;
+ basePath: $.ServiceDefinition.attributes.*
jsonMaps:
- - jsonPath: $.service.attributes.*.id
+ - jsonPath: $.ServiceDefinition.attributes.*.id
+
+ - jsonPath: $.ServiceDefinition.attributes.*.referenceId
+
+ - jsonPath: $.ServiceDefinition.attributes.*.tenantId
+
+ - jsonPath: $.ServiceDefinition.attributes.*.code
+
+ - jsonPath: $.ServiceDefinition.attributes.*.dataType
+
+ - jsonPath: $.ServiceDefinition.attributes.*.values
+ type: ARRAY
+ dbType: STRING
- - jsonPath: $.service.attributes.*.referenceId
+ - jsonPath: $.ServiceDefinition.attributes.*.isActive
- - jsonPath: $.service.attributes.*.attributeCode
+ - jsonPath: $.ServiceDefinition.attributes.*.required
- - jsonPath: $.service.attributes.*.value
+ - jsonPath: $.ServiceDefinition.attributes.*.regex
+
+ - jsonPath: $.ServiceDefinition.attributes.*.order
+
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdBy
+
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy
+
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.createdTime
+
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime
+
+ - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails
type: JSON
dbType: JSONB
- - jsonPath: $.service.attributes.*.auditDetails.createdBy
+ - jsonPath: $.ServiceDefinition.attributes.*.dataType
+
+ - jsonPath: $.ServiceDefinition.attributes.*.values
+ type: ARRAY
+ dbType: STRING
+
+ - jsonPath: $.ServiceDefinition.attributes.*.isActive
+
+ - jsonPath: $.ServiceDefinition.attributes.*.required
+
+ - jsonPath: $.ServiceDefinition.attributes.*.regex
- - jsonPath: $.service.attributes.*.auditDetails.lastModifiedBy
+ - jsonPath: $.ServiceDefinition.attributes.*.order
- - jsonPath: $.service.attributes.*.auditDetails.createdTime
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedBy
- - jsonPath: $.service.attributes.*.auditDetails.lastModifiedTime
+ - jsonPath: $.ServiceDefinition.attributes.*.auditDetails.lastModifiedTime
- - jsonPath: $.service.attributes.*.additionalDetails
+ - jsonPath: $.ServiceDefinition.attributes.*.additionalDetails
type: JSON
dbType: JSONB
\ No newline at end of file
diff --git a/health-services/census-service/CHANGELOG.md b/health-services/census-service/CHANGELOG.md
new file mode 100644
index 00000000000..38562489c90
--- /dev/null
+++ b/health-services/census-service/CHANGELOG.md
@@ -0,0 +1,13 @@
+# Changelog
+All notable changes to this module will be documented in this file.
+
+## 1.0.0 - 2024-11-28
+#### Census Service
+The Census Service introduces core functionalities for managing census data:
+
+1. Validation of Census: Ensures data integrity by validating all census requests before processing.
+2. Census Create: Creates new census records after validation and enrichment, publishing request to the designated Kafka topic to handle the creation process asynchronously.
+3. Census Update: Updates existing records post-validation and enrichment by sending request to the designated Kafka update topic.
+4. Census Bulk Update: Updates multiple census records in one operation after successful validation.
+5. Census Search: Enables searching for census records with the provided search criteria.
+6. Plan Facility Consumer: Listens to Plan Facility Update topic to assign facility to a boundary in census.
\ No newline at end of file
diff --git a/health-services/census-service/README.md b/health-services/census-service/README.md
new file mode 100644
index 00000000000..a2e8a9f7b84
--- /dev/null
+++ b/health-services/census-service/README.md
@@ -0,0 +1,18 @@
+# Swagger generated server
+
+Spring Boot Server
+
+
+## Overview
+This server was generated by the [swagger-codegen](https://github.com/swagger-api/swagger-codegen) project.
+By using the [OpenAPI-Spec](https://github.com/swagger-api/swagger-core), you can easily generate a server stub.
+This is an example of building a swagger-enabled server in Java using the SpringBoot framework.
+
+The underlying library integrating swagger to SpringBoot is [springfox](https://github.com/springfox/springfox)
+
+Start your server as an simple java application
+
+You can view the api documentation in swagger-ui by pointing to
+http://localhost:8080/
+
+Change default port value in application.properties
\ No newline at end of file
diff --git a/health-services/census-service/pom.xml b/health-services/census-service/pom.xml
new file mode 100644
index 00000000000..7e6f7adc8fb
--- /dev/null
+++ b/health-services/census-service/pom.xml
@@ -0,0 +1,141 @@
+
+ 4.0.0
+ org.egov
+ census-service
+ jar
+ census-service
+ 1.0.0
+
+ 17
+ ${java.version}
+ ${java.version}
+
+
+ org.springframework.boot
+ spring-boot-starter-parent
+ 3.2.2
+
+
+ src/main/java
+
+
+ org.springframework.boot
+ spring-boot-maven-plugin
+
+
+
+ repackage
+
+
+
+
+
+
+
+
+ org.springframework.boot
+ spring-boot-starter-web
+
+
+ org.egov.common
+ health-services-models
+ 1.0.21-SNAPSHOT
+ compile
+
+
+ junit
+ junit
+ 4.13.2
+ test
+
+
+ org.springframework.boot
+ spring-boot-starter-jdbc
+
+
+ org.flywaydb
+ flyway-core
+ 9.22.3
+
+
+ org.postgresql
+ postgresql
+ 42.7.1
+
+
+ org.springframework.boot
+ spring-boot-starter-test
+ test
+
+
+
+ io.swagger
+ swagger-core
+ 1.5.18
+
+
+ io.swagger.core.v3
+ swagger-annotations
+ 2.2.8
+
+
+ net.minidev
+ json-smart
+ 2.5.0
+
+
+
+ org.egov.services
+ tracer
+ 2.9.0-SNAPSHOT
+
+
+
+
+
+
+
+ org.egov
+ mdms-client
+ 2.9.0-SNAPSHOT
+ compile
+
+
+ org.projectlombok
+ lombok
+ true
+
+
+
+ com.fasterxml.jackson.datatype
+ jackson-datatype-jsr310
+
+
+
+ org.springframework.boot
+ spring-boot-starter-validation
+
+
+
+
+ repo.egovernments.org
+ eGov ERP Releases Repository
+ https://nexus-repo.egovernments.org/nexus/content/repositories/releases/
+
+
+ repo.egovernments.org.snapshots
+ eGov ERP Releases Repository
+ https://nexus-repo.egovernments.org/nexus/content/repositories/snapshots/
+
+
+ repo.egovernments.org.public
+ eGov Public Repository Group
+ https://nexus-repo.egovernments.org/nexus/content/groups/public/
+
+
+ repo.digit.org
+ eGov DIGIT Releases Repository
+ https://nexus-repo.digit.org/nexus/content/repositories/snapshots/
+
+
+
diff --git a/health-services/census-service/src/main/java/digit/Main.java b/health-services/census-service/src/main/java/digit/Main.java
new file mode 100644
index 00000000000..6e3d79db11c
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/Main.java
@@ -0,0 +1,20 @@
+package digit;
+
+
+import org.egov.tracer.config.TracerConfiguration;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.context.annotation.Import;
+
+@Import({ TracerConfiguration.class })
+@SpringBootApplication
+@ComponentScan(basePackages = { "digit", "digit.web.controllers" , "digit.config"})
+public class Main {
+
+
+ public static void main(String[] args) throws Exception {
+ SpringApplication.run(Main.class, args);
+ }
+
+}
diff --git a/health-services/census-service/src/main/java/digit/config/Configuration.java b/health-services/census-service/src/main/java/digit/config/Configuration.java
new file mode 100644
index 00000000000..8459885357e
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/config/Configuration.java
@@ -0,0 +1,86 @@
+package digit.config;
+
+import lombok.*;
+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 java.util.List;
+
+@Component
+@Data
+@Import({TracerConfiguration.class})
+@NoArgsConstructor
+@AllArgsConstructor
+@Setter
+@Getter
+public class Configuration {
+
+ // Allowed roles for census
+ @Value("#{${allowed.census.roles}}")
+ private List allowedCensusRoles;
+
+ @Value("#{${workflow.restricted.roles}}")
+ private List workflowRestrictedRoles;
+
+ // Persister Topic
+ @Value("${census.create.topic}")
+ private String censusCreateTopic;
+
+ @Value("${census.update.topic}")
+ private String censusUpdateTopic;
+
+ @Value("${census.bulk.update.topic}")
+ private String censusBulkUpdateTopic;
+
+ @Value("${plan.facility.update.topic}")
+ private String planFcailityUpdateTopic;
+
+ // Boundary Service
+ @Value("${egov.boundary.service.host}")
+ private String boundaryServiceHost;
+
+ @Value("${egov.boundary.relationship.search.endpoint}")
+ private String boundaryRelationshipSearchEndpoint;
+
+ @Value("${egov.boundary.hierarchy.search.endpoint}")
+ private String boundaryHierarchySearchEndpoint;
+
+ // Plan Service
+ @Value("${egov.plan.service.host}")
+ private String planServiceHost;
+
+ @Value("${egov.plan.employee.assignment.search.endpoint}")
+ private String planEmployeeAssignmentSearchEndpoint;
+
+ //Workflow
+ @Value("${egov.workflow.host}")
+ private String wfHost;
+
+ @Value("${egov.workflow.transition.path}")
+ private String wfTransitionPath;
+
+ @Value("${egov.business.service.search.endpoint}")
+ private String businessServiceSearchEndpoint;
+
+ @Value("${workflow.initiate.action}")
+ private List wfInitiateActions;
+
+ @Value("${workflow.intermediate.action}")
+ private List wfIntermediateActions;
+
+ @Value("${workflow.send.back.actions}")
+ private List wfSendBackActions;
+
+ //SMSNotification
+ @Value("${egov.sms.notification.topic}")
+ private String smsNotificationTopic;
+
+ //Pagination
+ @Value("${census.default.offset}")
+ private Integer defaultOffset;
+
+ @Value("${census.default.limit}")
+ private Integer defaultLimit;
+}
diff --git a/health-services/census-service/src/main/java/digit/config/MainConfiguration.java b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java
new file mode 100644
index 00000000000..239331c9cd8
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/config/MainConfiguration.java
@@ -0,0 +1,41 @@
+package digit.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Import;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.http.MediaType;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+
+import java.util.TimeZone;
+
+import jakarta.annotation.PostConstruct;
+import com.fasterxml.jackson.databind.DeserializationFeature;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.egov.tracer.config.TracerConfiguration;
+
+
+@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/health-services/census-service/src/main/java/digit/config/ServiceConstants.java b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java
new file mode 100644
index 00000000000..5d944060848
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/config/ServiceConstants.java
@@ -0,0 +1,114 @@
+package digit.config;
+
+
+import org.springframework.stereotype.Component;
+
+
+@Component
+public class ServiceConstants {
+
+ public static final String EXTERNAL_SERVICE_EXCEPTION = "External Service threw an Exception: ";
+ public static final String SEARCHER_SERVICE_EXCEPTION = "Exception while fetching from searcher: ";
+
+ public static final String IDGEN_ERROR = "IDGEN ERROR";
+ public static final String NO_IDS_FOUND_ERROR = "No ids returned from idgen Service";
+
+ public static final String ERROR_WHILE_FETCHING_FROM_MDMS = "Exception occurred while fetching category lists from mdms: ";
+
+ public static final String ERROR_WHILE_FETCHING_BOUNDARY_DETAILS = "Exception occurred while fetching boundary relationship from boundary service: ";
+
+ public static final String ERROR_WHILE_FETCHING_BOUNDARY_HIERARCHY_DETAILS = "Exception occurred while fetching boundary hierarchy details from boundary service: ";
+
+ public static final String ERROR_WHILE_FETCHING_EMPLOYEE_ASSIGNMENT_DETAILS = "Exception occurred while fetching plan employee assignment details from plan service: ";
+
+ public static final String ERROR_WHILE_FETCHING_BUSINESS_SERVICE_DETAILS = "Exception occurred while fetching business service details: ";
+
+ public static final String RES_MSG_ID = "uief87324";
+ public static final String SUCCESSFUL = "successful";
+ public static final String FAILED = "failed";
+
+ public static final String URL = "url";
+ public static final String URL_SHORTENING_ERROR_CODE = "URL_SHORTENING_ERROR";
+ public static final String URL_SHORTENING_ERROR_MESSAGE = "Unable to shorten url: ";
+
+ public static final String DOB_FORMAT_Y_M_D = "yyyy-MM-dd";
+ public static final String DOB_FORMAT_D_M_Y = "dd/MM/yyyy";
+ public static final String ILLEGAL_ARGUMENT_EXCEPTION_CODE = "IllegalArgumentException";
+ public static final String OBJECTMAPPER_UNABLE_TO_CONVERT = "ObjectMapper not able to convertValue in userCall";
+ public static final String DOB_FORMAT_D_M_Y_H_M_S = "dd-MM-yyyy HH:mm:ss";
+ public static final String CREATED_DATE = "createdDate";
+ public static final String LAST_MODIFIED_DATE = "lastModifiedDate";
+ public static final String DOB = "dob";
+ public static final String PWD_EXPIRY_DATE = "pwdExpiryDate";
+ public static final String INVALID_DATE_FORMAT_CODE = "INVALID_DATE_FORMAT";
+ public static final String INVALID_DATE_FORMAT_MESSAGE = "Failed to parse date format in user";
+ public static final String CITIZEN_UPPER = "CITIZEN";
+ public static final String CITIZEN_LOWER = "Citizen";
+ public static final String USER = "user";
+ public static final String PIPE_REGEX = "\\|";
+ public static final String FACILITY_ID_FIELD = "facilityId";
+ public static final String FACILITY_NAME_FIELD = "facilityName";
+
+ public static final String PARSING_ERROR_CODE = "PARSING ERROR";
+ public static final String PARSING_ERROR_MESSAGE = "Failed to parse JSON data from PGobject";
+
+ public static final String FAILED_TO_PARSE_BUSINESS_SERVICE_SEARCH = "Failed to parse response of workflow business service search";
+ public static final String BUSINESS_SERVICE_NOT_FOUND = "BUSINESSSERVICE_NOT_FOUND";
+ public static final String THE_BUSINESS_SERVICE = "The businessService ";
+ public static final String NOT_FOUND = " is not found";
+ public static final String TENANTID = "?tenantId=";
+ public static final String BUSINESS_SERVICES = "&businessServices=";
+
+ public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_CODE = "NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE";
+ public static final String NO_BOUNDARY_DATA_FOUND_FOR_GIVEN_BOUNDARY_CODE_MESSAGE = "Invalid or incorrect boundaryCode. No boundary data found.";
+
+ public static final String NO_BUSINESS_SERVICE_DATA_FOUND_CODE = "NO_BUSINESS_SERVICE_DATA_FOUND";
+ public static final String NO_BUSINESS_SERVICE_DATA_FOUND_MESSAGE = "Invalid or incorrect businessService. No business service data found.";
+
+ public static final String USERINFO_MISSING_CODE = "USERINFO_MISSING";
+ public static final String USERINFO_MISSING_MESSAGE = "UserInfo is missing in Request Info ";
+
+ public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_CODE = "ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS";
+ public static final String ERROR_WHILE_UPDATING_ADDITIONAL_DETAILS_MESSAGE = "Exception occurred while updating additional details : ";
+
+ public static final String WORKFLOW_INTEGRATION_ERROR_CODE = "WORKFLOW_INTEGRATION_ERROR";
+ public static final String WORKFLOW_INTEGRATION_ERROR_MESSAGE = "Exception occured while integrating with workflow : ";
+
+ public static final String INVALID_PARTNER_CODE = "INVALID_PARTNER";
+ public static final String INVALID_PARTNER_MESSAGE = "Invalid partner assignment or invalid jurisdiction of the assigned partner";
+
+ public static final String INVALID_CENSUS_CODE = "INVALID_CENSUS";
+ public static final String INVALID_CENSUS_MESSAGE = "Provided census does not exist";
+
+ public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_CODE = "DUPLICATE_CENSUS_ID_IN_BULK_UPDATE";
+ public static final String DUPLICATE_CENSUS_ID_IN_BULK_UPDATE_MESSAGE = "Census provided in the bulk update request are not unique.";
+
+ public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_CODE = "INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE";
+ public static final String INVALID_SOURCE_OR_TENANT_ID_FOR_BULK_UPDATE_MESSAGE = "Tenant id and source should be same across all entries for bulk update.";
+
+ public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_CODE = "WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE";
+ public static final String WORKFLOW_NOT_FOUND_FOR_BULK_UPDATE_MESSAGE = "Workflow information is mandatory for each entry for bulk update";
+
+ public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_CODE = "DUPLICATE_KEY_IN_ADDITIONAL_FIELD";
+ public static final String DUPLICATE_KEY_IN_ADDITIONAL_FIELD_MESSGAE = "Duplicate key found in additional field : ";
+
+ public static final String CENSUS_ALREADY_EXISTS_CODE = "CENSUS_ALREADY_EXISTS";
+ public static final String CENSUS_ALREADY_EXISTS_MESSAGE = "Census with the given boundary and source already exists.";
+
+ public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_CODE = "DIFFERENT_WORKFLOW_FOR_BULK_UPDATE";
+ public static final String DIFFERENT_WORKFLOW_FOR_BULK_UPDATE_MESSAGE = "All entries should be in the same state for bulk transitioning census records.";
+
+ public static final String UNAUTHORIZED_WORKFLOW_ACCESS_CODE = "UNAUTHORIZED_WORKFLOW_ACCESS";
+ public static final String UNAUTHORIZED_WORKFLOW_ACCESS_MESSAGE = "User with provided roles cannot have an active workflow. Please remove the workflow or update user roles.";
+
+ public static final String SEARCH_CRITERIA_EMPTY_CODE = "SEARCH_CRITERIA_EMPTY";
+ public static final String SEARCH_CRITERIA_EMPTY_MESSAGE = "Search criteria cannot be empty";
+
+ public static final String TENANT_ID_EMPTY_CODE = "TENANT_ID_EMPTY";
+ public static final String TENANT_ID_EMPTY_MESSAGE = "Tenant Id cannot be empty, TenantId should be present";
+
+ //Workflow constants
+ public static final String MODULE_NAME_VALUE = "census-service";
+
+ public static final String CENSUS_BUSINESS_SERVICE = "CENSUS";
+}
diff --git a/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java
new file mode 100644
index 00000000000..d5be4b7458c
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/kafka/FacilityCatchmentConsumer.java
@@ -0,0 +1,99 @@
+package digit.kafka;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import digit.repository.CensusRepository;
+import digit.service.CensusService;
+import digit.service.enrichment.CensusEnrichment;
+import digit.util.BoundaryUtil;
+import digit.util.CommonUtil;
+import digit.web.models.BulkCensusRequest;
+import digit.web.models.Census;
+import digit.web.models.CensusResponse;
+import digit.web.models.boundary.BoundaryTypeHierarchyResponse;
+import digit.web.models.plan.PlanFacilityDTO;
+import digit.web.models.plan.PlanFacilityRequestDTO;
+import lombok.extern.slf4j.Slf4j;
+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.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static digit.config.ServiceConstants.FACILITY_ID_FIELD;
+import static digit.config.ServiceConstants.FACILITY_NAME_FIELD;
+
+@Component
+@Slf4j
+public class FacilityCatchmentConsumer {
+
+ private ObjectMapper objectMapper;
+
+ private CensusService service;
+
+ private CensusRepository repository;
+
+ private CommonUtil commonUtil;
+
+ private BoundaryUtil boundaryUtil;
+
+ private CensusEnrichment enrichment;
+
+ public FacilityCatchmentConsumer(ObjectMapper objectMapper, CensusService service, CommonUtil commonUtil, CensusRepository repository, BoundaryUtil boundaryUtil, CensusEnrichment enrichment) {
+ this.objectMapper = objectMapper;
+ this.service = service;
+ this.commonUtil = commonUtil;
+ this.repository = repository;
+ this.boundaryUtil = boundaryUtil;
+ this.enrichment = enrichment;
+ }
+
+ @KafkaListener(topics = {"${plan.facility.update.topic}"})
+ public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
+ try {
+ PlanFacilityRequestDTO planFacilityRequestDTO = objectMapper.convertValue(consumerRecord, PlanFacilityRequestDTO.class);
+ PlanFacilityDTO planFacilityDTO = planFacilityRequestDTO.getPlanFacilityDTO();
+
+ CensusResponse censusResponse = service.search(commonUtil.getCensusSearchRequest(planFacilityDTO.getTenantId(), planFacilityDTO.getPlanConfigurationId(), planFacilityDTO.getServiceBoundaries(), planFacilityDTO.getInitiallySetServiceBoundaries(), planFacilityRequestDTO.getRequestInfo()));
+ List censusFromSearch = censusResponse.getCensus();
+
+ BoundaryTypeHierarchyResponse boundaryTypeHierarchyResponse = boundaryUtil.fetchBoundaryHierarchy(planFacilityRequestDTO.getRequestInfo(), censusFromSearch.get(0).getTenantId(), censusFromSearch.get(0).getHierarchyType());
+ String facilityId = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityId();
+ String facilityName = planFacilityRequestDTO.getPlanFacilityDTO().getFacilityName();
+
+ Set boundariesWithFacility = new HashSet<>(List.of(planFacilityDTO.getServiceBoundaries().split(",")));
+ Set boundariesWithNoFacility = new HashSet<>(planFacilityDTO.getInitiallySetServiceBoundaries());
+
+ censusFromSearch.forEach(census -> {
+ String boundaryCode = census.getBoundaryCode();
+
+ if (!boundariesWithFacility.contains(boundaryCode)) {
+
+ // Unassigning facilities to the boundaries which were initially assigned that facility
+ census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD));
+ census.setAdditionalDetails(commonUtil.removeFieldFromAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD));
+ census.setFacilityAssigned(Boolean.FALSE);
+ census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);
+
+ } else if (!boundariesWithNoFacility.contains(boundaryCode)) {
+
+ // Assigning facilities to the newly added boundaries in the update request.
+ census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_ID_FIELD, facilityId));
+ census.setAdditionalDetails(commonUtil.updateFieldInAdditionalDetails(census.getAdditionalDetails(), FACILITY_NAME_FIELD, facilityName));
+ census.setFacilityAssigned(Boolean.TRUE);
+ census.setPartnerAssignmentValidationEnabled(Boolean.FALSE);
+ }
+ });
+
+ // Enrich jurisdiction mapping in census for indexer
+ enrichment.enrichJurisdictionMapping(censusFromSearch, boundaryTypeHierarchyResponse.getBoundaryHierarchy().get(0));
+ repository.bulkUpdate(BulkCensusRequest.builder().requestInfo(planFacilityRequestDTO.getRequestInfo()).census(censusFromSearch).build());
+
+ } catch (Exception exception) {
+ log.error("Error in census consumer", exception);
+ }
+ }
+}
diff --git a/health-services/census-service/src/main/java/digit/kafka/Producer.java b/health-services/census-service/src/main/java/digit/kafka/Producer.java
new file mode 100644
index 00000000000..542f4f686c0
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/kafka/Producer.java
@@ -0,0 +1,20 @@
+package digit.kafka;
+
+import lombok.extern.slf4j.Slf4j;
+import org.egov.tracer.kafka.CustomKafkaTemplate;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+// NOTE: If tracer is disabled change CustomKafkaTemplate to KafkaTemplate in autowiring
+
+@Service
+@Slf4j
+public class Producer {
+
+ @Autowired
+ private CustomKafkaTemplate kafkaTemplate;
+
+ public void push(String topic, Object value) {
+ kafkaTemplate.send(topic, value);
+ }
+}
diff --git a/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java
new file mode 100644
index 00000000000..e161225b23a
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/kafka/ResourceCensusConsumer.java
@@ -0,0 +1,37 @@
+package digit.kafka;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import digit.service.CensusService;
+import digit.web.models.CensusRequest;
+import lombok.extern.slf4j.Slf4j;
+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.Map;
+
+@Component
+@Slf4j
+public class ResourceCensusConsumer {
+
+ private CensusService censusService;
+
+ private ObjectMapper mapper;
+
+ public ResourceCensusConsumer(CensusService censusService, ObjectMapper mapper) {
+ this.censusService = censusService;
+ this.mapper = mapper;
+ }
+
+ @KafkaListener(topics = {"${resource.config.consumer.census.create.topic}"})
+ public void listen(Map consumerRecord, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
+ try {
+ CensusRequest censusRequest = mapper.convertValue(consumerRecord, CensusRequest.class);
+ censusRequest.getCensus().setPartnerAssignmentValidationEnabled(Boolean.FALSE);
+ censusService.create(censusRequest);
+ } catch (Exception exception) {
+ log.error("Error in resource census consumer", exception);
+ }
+ }
+}
diff --git a/health-services/census-service/src/main/java/digit/repository/CensusRepository.java b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java
new file mode 100644
index 00000000000..4a9f159e7e9
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/repository/CensusRepository.java
@@ -0,0 +1,21 @@
+package digit.repository;
+
+import digit.web.models.*;
+
+import java.util.List;
+import java.util.Map;
+
+public interface CensusRepository {
+
+ public void create(CensusRequest censusRequest);
+
+ public List search(CensusSearchCriteria censusSearchCriteria);
+
+ public void update(CensusRequest censusRequest);
+
+ public void bulkUpdate(BulkCensusRequest request);
+
+ public Integer count(CensusSearchCriteria censusSearchCriteria);
+
+ public Map statusCount(CensusSearchRequest censusSearchRequest);
+}
diff --git a/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java
new file mode 100644
index 00000000000..d09d230e4fa
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/repository/ServiceRequestRepository.java
@@ -0,0 +1,45 @@
+package digit.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;
+
+import static digit.config.ServiceConstants.*;
+
+@Repository
+@Slf4j
+public class ServiceRequestRepository {
+
+ private ObjectMapper mapper;
+
+ private RestTemplate restTemplate;
+
+ public ServiceRequestRepository(ObjectMapper mapper, RestTemplate restTemplate) {
+ this.mapper = mapper;
+ this.restTemplate = restTemplate;
+ }
+
+
+ public Object fetchResult(StringBuilder uri, Object request) {
+ mapper.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS, false);
+ Object response = null;
+ try {
+ response = restTemplate.postForObject(uri.toString(), request, Map.class);
+ } catch (HttpClientErrorException e) {
+ log.error(EXTERNAL_SERVICE_EXCEPTION, e);
+ throw new ServiceCallException(e.getResponseBodyAsString());
+ } catch (Exception e) {
+ log.error(SEARCHER_SERVICE_EXCEPTION, e);
+ }
+
+ return response;
+ }
+}
\ No newline at end of file
diff --git a/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java
new file mode 100644
index 00000000000..c6dec4b4d11
--- /dev/null
+++ b/health-services/census-service/src/main/java/digit/repository/impl/CensusRepositoryImpl.java
@@ -0,0 +1,219 @@
+package digit.repository.impl;
+
+import digit.config.Configuration;
+import digit.kafka.Producer;
+import digit.repository.CensusRepository;
+import digit.repository.querybuilder.CensusQueryBuilder;
+import digit.repository.rowmapper.CensusRowMapper;
+import digit.repository.rowmapper.StatusCountRowMapper;
+import digit.util.CommonUtil;
+import digit.web.models.*;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.core.SingleColumnRowMapper;
+import org.springframework.stereotype.Repository;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.ObjectUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+import static digit.config.ServiceConstants.CENSUS_BUSINESS_SERVICE;
+
+@Slf4j
+@Repository
+public class CensusRepositoryImpl implements CensusRepository {
+
+ private Producer producer;
+
+ private Configuration config;
+
+ private CensusQueryBuilder queryBuilder;
+
+ private CensusRowMapper censusRowMapper;
+
+ private JdbcTemplate jdbcTemplate;
+
+ private StatusCountRowMapper statusCountRowMapper;
+
+ private CommonUtil commonUtil;
+
+ public CensusRepositoryImpl(Producer producer, Configuration config, CensusQueryBuilder queryBuilder, CensusRowMapper censusRowMapper, JdbcTemplate jdbcTemplate, StatusCountRowMapper statusCountRowMapper,CommonUtil commonUtil) {
+ this.producer = producer;
+ this.config = config;
+ this.queryBuilder = queryBuilder;
+ this.censusRowMapper = censusRowMapper;
+ this.jdbcTemplate = jdbcTemplate;
+ this.statusCountRowMapper = statusCountRowMapper;
+ this.commonUtil = commonUtil;
+ }
+
+ /**
+ * Pushes a new census record to persister kafka topic.
+ *
+ * @param censusRequest The request containing the census details
+ */
+ @Override
+ public void create(CensusRequest censusRequest) {
+ CensusRequestDTO requestDTO = convertToReqDTO(censusRequest);
+ producer.push(config.getCensusCreateTopic(), requestDTO);
+ }
+
+ /**
+ * Searches for census records based on the provided search criteria.
+ *
+ * @param censusSearchCriteria The criteria to use for searching census records.
+ * @return A list of census records that match the search criteria.
+ */
+ @Override
+ public List search(CensusSearchCriteria censusSearchCriteria) {
+
+ if(censusSearchCriteria.getAreaCodes() != null && censusSearchCriteria.getAreaCodes().isEmpty())
+ return new ArrayList<>();
+
+ // Fetch census ids from database
+ List censusIds = queryDatabaseForCensusIds(censusSearchCriteria);
+
+ // Return empty list back as response if no census ids are found
+ if(CollectionUtils.isEmpty(censusIds)) {
+ log.info("No census ids found for provided census search criteria.");
+ return new ArrayList<>();
+ }
+
+ // Fetch census from database based on the acquired ids
+ return searchCensusByIds(censusIds);
+ }
+
+ private List searchCensusByIds(List censusIds) {
+
+ List